首先我们来谈谈jdk的动态代理,它允许开发者在运行期创建接口的代理实例,那么当我们在运行过程中调用某个实例的某个方法时,可以使用代理对象去具体实现它,从而达到aop的效果。 (1)jdk的动态代理主要涉及两个类:proxy和invocacationHandler,invocationHandler里面包含了横切逻辑,并且可以使用反射调用目标类的方法(就是切点),proxy类主要是使用它的一个newinstance方法去创建一个代理实例。 下面我们来看代码: - package com.yue.test;
-
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
-
- public class testHandler implements InvocationHandler{
- private Object target;
- public testHandler(Object o){
- this.target = o;
- }
-
- /*
- * 这里的method对象是java反射机制中的方法反射类对象,通过这个方法反射对象可以调用目标对象中的方法
- * 里面的target是目标类对象,利用反射在目标类对象中找到对应的方法传入参数后调用
- * 也可以说是根据目标对象得到的代理对象是在目标对象的基础上插入了横切逻辑的
- * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
- */
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- System.out.println("hey");
- Object obj = method.invoke(target, args);
- System.out.println("end!");
- return obj;
- }
-
- }
package com.yue.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class testHandler implements InvocationHandler{
private Object target;
public testHandler(Object o){
this.target = o;
}
/*
* 这里的method对象是java反射机制中的方法反射类对象,通过这个方法反射对象可以调用目标对象中的方法
* 里面的target是目标类对象,利用反射在目标类对象中找到对应的方法传入参数后调用
* 也可以说是根据目标对象得到的代理对象是在目标对象的基础上插入了横切逻辑的
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("hey");
Object obj = method.invoke(target, args);
System.out.println("end!");
return obj;
}
}
- package com.yue.test;
-
-
-
- public class PrivateCar implements Car{
-
-
- public void say(){
- System.out.println("spring is fun!");
- }
- }
package com.yue.test;
public class PrivateCar implements Car{
public void say(){
System.out.println("spring is fun!");
}
}
- package com.yue.test;
-
- public interface Car {
- public void say();
- }
package com.yue.test;
public interface Car {
public void say();
}
- package com.yue.test;
-
- import java.lang.reflect.Proxy;
-
-
-
-
- public class Test {
-
- public static void main(String[] args){
- PrivateCar pc = new PrivateCar();
- testHandler th = new testHandler(pc);
- //这里因为生成的代理对象实现了目标对象的所有接口,所以根据多态可以变为Car类型
- Car car = (Car)Proxy.newProxyInstance(pc.getClass().getClassLoader(), pc.getClass().getInterfaces(), th);
- car.say();
-
-
- }
-
-
- }
package com.yue.test;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args){
PrivateCar pc = new PrivateCar();
testHandler th = new testHandler(pc);
//这里因为生成的代理对象实现了目标对象的所有接口,所以根据多态可以变为Car类型
Car car = (Car)Proxy.newProxyInstance(pc.getClass().getClassLoader(), pc.getClass().getInterfaces(), th);
car.say();
}
}
得到的结果是: hey
spring is fun!
end!
所以我们可以看到,jdk动态代理的局限在于它只是在接口层次上的实现,不能用在子类上 (2)若要不是用于接口定义,则需要用到cglib代理(这里需要格外引入jar包) cglib代理使用底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,织入横切逻辑 下面我们来看看代码: - package com.yue.test;
-
-
-
-
-
- public class Test {
-
- public static void main(String[] args){
- CglibProxy cp = new CglibProxy();
- PrivateCar pc = (PrivateCar)cp.getProxy(PrivateCar.class);
- pc.say();
- }
-
-
- }
package com.yue.test;
public class Test {
public static void main(String[] args){
CglibProxy cp = new CglibProxy();
PrivateCar pc = (PrivateCar)cp.getProxy(PrivateCar.class);
pc.say();
}
}
- package com.yue.test;
-
- import java.lang.reflect.Method;
-
- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
-
- public class CglibProxy implements MethodInterceptor{
- private Enhancer enhancer = new Enhancer();
- /*
- * 这里的setSuperClass表示创建的代理对象是这个类的子类
- * create方法表示使用字节码的方式创建子类对象
- */
- public Object getProxy(Class clazz){
- enhancer.setSuperclass(clazz);
- enhancer.setCallback(this);
- return enhancer.create();
- }
-
- /*
- * 每个父类方法的调用,都会被这个intercept方法拦截住,并且织入横切逻辑
- * 这里的methodProxy对象也是利用java的反射机制去执行父类中的业务方法
- * @see net.sf.cglib.proxy.MethodInterceptor#intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], net.sf.cglib.proxy.MethodProxy)
- */
- @Override
- public Object intercept(Object arg0, Method arg1, Object[] arg2,
- MethodProxy arg3) throws Throwable {
- System.out.println("heycglib");
- Object obj = arg3.invokeSuper(arg0, arg2);
- return obj;
- }
-
- }
package com.yue.test;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
/*
* 这里的setSuperClass表示创建的代理对象是这个类的子类
* create方法表示使用字节码的方式创建子类对象
*/
public Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/*
* 每个父类方法的调用,都会被这个intercept方法拦截住,并且织入横切逻辑
* 这里的methodProxy对象也是利用java的反射机制去执行父类中的业务方法
* @see net.sf.cglib.proxy.MethodInterceptor#intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], net.sf.cglib.proxy.MethodProxy)
*/
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
System.out.println("heycglib");
Object obj = arg3.invokeSuper(arg0, arg2);
return obj;
}
}
总结:由于cglib代理创建代理对象时间比jdk代理多了差不多8倍,而创建出来的代理运行速率差不多是jdk创建出来的10倍,所以一般单例我们都使用cglib代理,prototype就是用jdk代理
这里我们还必须注意的是,因为jdk动态代理是使用接口创建,cglib动态代理创建的是子类代理,所以: (1)jdk:除public外的所有方法都不可以被增强(注意public static也是不可以的)
(2)cglib:private,static、final方法都不可以
|