`
xifangyuhui
  • 浏览: 185814 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JAVA反射机制的应用(2)

阅读更多

JAVA反射机制的应用(2)

Spring中的AOP(面向切面的编程)

在MVC中,业务层对象扮演了相当重要的作用,它的方法代表了核心业务逻辑,但是可能还有一些附加的操作,比如写日志等其它操作也会包含在其中,那么可能会带来几个问题:

  • 冗余代码的出现
  • 破坏了面向对象的思想。各个方法应该各司其职,只做它应该做的那一部分工作,而这里这些辅助操作的引入会破坏这个特性。

这里我们把这些附加操作(比如写日志操作)看成一个切面,并且把它从业务方法中抽离出来,然后把它植入到各个业务方法中,这样维护这些辅助操作是相当容易了,而且也不会出现冗余代码。那么这种思想怎么实现呢?

这里把上面提到的业务对象称为目标对象,再引入一个委托对象(下面会讲到两种委托对象),我们不直接对目标对象进行操作,而是对委托对象进行方法调用,在委托对象的方法中可以完成切面操作,接着再把方法调用转交到相应的目标对象上。

 

AOP的两种实现方式:

(1)CgLib 运行时代码增强工具,它是一个第三方的工具,运行时使用cglib可以 动态地给一个类生成一个子类 ,并使用子类对象作为父类对象的委托。 CGLIB包对代理那些没有实现接口的类非常有用。 它是通过动态的生成一个子类去覆盖所要代理类的不是final的方法,并设置好callback ,setCallback的参数是一个MethodInterceptor接口的实现类实例,则原有类的每个方法调用就会转变成调用用户在 MethodInterceptor 自定义的拦截方法(intercept)。 在这个拦截方法中,我们可以在intercept方法中首先处理我们要辅助的逻辑,完了之后再使用 proxy.invokeSuper(o, os)来调用父类中的相应 方法来处理

步骤:首先需要一个cglib的jar包,并配置到classPath中,cglib有一个核心接口:MethodInterceptor接口,我们需要创建类来实现这个接口,并实现其中的方法:

public Object intercept(Object o, Method m, Object[] os, MethodProxy proxy)

该方法中我们可以定义一些特殊的逻辑,比如写日志等操作,这些操作完了之后再调用父类中的相关方法。

除此之外,在该类中还要创建一个Enhancer对象,参考以下内容

用Enhancer生成一个原有类的子类,并且设置好callback , 则 原有类的每个方法调用都会转成调用实现了MethodInterceptor接口的proxy的intercept() 函数       public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy)  

     在intercept()函数里,你可以执行Object result=proxy.invokeSuper(o,args)来执行原有函数,在执行前后加入自己的东西,改变它的参数,也可以瞒天过海,完全干别 的。说白了,就是AOP中的around advice。

public class TestCglibProxy {
	public static void main(String[] args) {
		AProxy ap=new AProxy();
		A a=(A)ap.getProxy(A.class);   //利用cglib创建A类的子类对象(代理对象)
  		a.method1();   //调用父对象的method1方法时会会调用代理对象的intercept方法
                a.method2();
	}
}

class A{
	public void method1(){
		System.out.println("A method1");
	}
	public void method2(){
		System.out.println("A method2");
	}
}

class AProxy implements MethodInterceptor{
	private Logger log=Logger.getLogger("A");
	private Enhancer en=new Enhancer();
	public Object getProxy(Class c){   //c是所要代理的父类的Class对象
                en.setCallback(this);  //表示调用父对象的方法时,回调当前对象的intercept方法
    		en.setSuperclass(c);  //设置父类对象
 		return en.create();    //创建一个代理类的实例
 }
	public Object intercept(Object o, Method m, Object[] os, MethodProxy proxy) throws Throwable {
		log.info("invoke method "+m.getName());
		Object result=proxy.invokeSuper(o, os);
		return result;
	}
} 


(2)动态代理方式

目标类T和代理类P都实现同样一个接口I 其中 P类对象中包含了一个T类的对象 ,在P和T实现接口I的同一个方法M时,可以在P中的M中调用T的M 方法 同时在调用T的M之前或者之后进行一些自定义的操作。

一个简单的代理模式实现

Interface I{

   void method1();

}

class T implements I{

  public void method() {

   ...

}

}

class P implements I {

private T t;

public P(T t) {

this.t = t;

}

public void methid() {

//do something

t.method();

//do something

}

}

上面的代码相信大家都能看懂 ,这就是一个代理模式的简单实现。

下面来介绍一下JAVA中已有的动态代理框架,三个关键类:Proxy,InvocationHandler,Method对象,首先我们需要创建目标类动态代理对象,怎么创建呢?调用:

 

newProxyInstance ( ClassLoader loader, Class <?>[] interfaces, InvocationHandler h)

前面讲过了代理类和目标类实现共同的接口,因此需要将目标类所实现的接口(这里是一个Class数组)传给Proxy,除此之外还需要传 递目标类的类加载器和InvocationHandler实例,类加载器当然是用来加载生成的代理类的class文件,而这里的 InvocationHandler是什么呢?顾名思义,调用处理器,当对代理类调用相应的方法时(这里的方法其实是我们想对目标类调用的),该方法调用 会被拦截,并回调InvocationHandler实现类的invoke方法,我们来简单看看invoke方法:

 

invoke ( Object  proxy, Method  method, Object [] args)

invoke方法中又包含了三个参数,第一个是代理对象proxy,第二个是Method对象,第三个是一个Object数组,这里简单介绍下这三个参 数:proxy对象大家应该都知道了,即代理对象 上面利用Proxy的静态newProxyInstance方法创建的 ;method对象,即方法对象,这里的方法对象是什么呢?刚才说到了对代理对象调用方法时会被拦截,而这里的method就是被拦截的方法对象 最后一个是args,相信大家对这个变量不会陌生,这里表示的是对代理对象调用方法时所传递的参数,参数可能为一个,两个或者多个,当然也可能没有,因此这里用一个数组表示。

肯定有人会问我在这个方法里写什么呢?爱写什么你写什么,呵呵,开个玩笑。 按照常理来说,这里面肯定会调用目标对象的method方法了,不然这代理还有什么意义!!!那怎么调用呢?相信有java反射基础的人大家应该都知道吧,不知道或者不熟练就查查API:

 

invoke ( Object obj, Object ... args)

第 一个对象是目标对象,第二个是参数数组,这里又涉及问题,怎么把目标对象传递到这儿呢?我这里介绍两种方法,其实大家应该都能想到,在定义 InvocationHandler实现类时,把目标类作为它的成员变量,通过构造函数把目标对象赋值给它,那么在invoke方法中当然就可以直接使用 了;另外一种更简单的方法,InvocationHandler的实例使用匿名内部类创建:

new InvocationHandler() {

    public  Object invoke(Object proxy, Method method, Object[] args)  {

       ...

      method,invoke(target, args);

      ...

    }

}

这里的target可以来自方法参数,但一定要是final的。

public class TestProxy {
	public static void main(String[] args){
		/*
		I target=new Target();
		I proxy=(I)ProxyFactory.getProxy(target);
		proxy.method();
		*/
		List list=new ArrayList();
		List listProxy=(List)ProxyFactory.getProxy(list);
		listProxy.add("abc");
		listProxy.add("def");
		listProxy.add(0,"123");
		listProxy.remove(1);
		listProxy.size();
		for(Object o:list){
			System.out.println(o);
		}
	}
}
interface I{
	void method();
}
class Target implements I{
	public void method(){
		System.out.println("Target method");
	}
}
class TargetProxy implements I{
	I target;
	public TargetProxy(I target){
		this.target=target;
	}
	public void method(){
		System.out.println("do sth in proxy");
		target.method();
	}
}
class ProxyFactory{
	public static Object getProxy(final Object target){
		Class c=target.getClass();
		ClassLoader loader=c.getClassLoader();
		Class[] is=c.getInterfaces();
		return Proxy.newProxyInstance(loader,is,new InvocationHandler(){
			public Object invoke(Object proxy, Method m, Object[] os) throws Throwable {
				System.out.println("invoke "+m.getName());
				return m.invoke(target, os);
			}
		});
	}
}
 

以上内容部分来自:http://nucchenyibin.iteye.com/blog/667733

                           http://www.zx2010.com/program/java-cglib-proxy.asp

 

0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics