在Spring中使用了两种AOP动态代理
JDK动态代理
一种是通过使用叫java的动态代理(dynamic proxies),这种代理只能为接口创建代理实例,而且可以代理任何的接口类;
Java的动态代理是采用JDK的动态代理机制实现的,JDK动态代理主要涉及两个类。
①Java.lang.reflect.Proxy
②Java.lang.reflect.InvocationHandler
JDK代理中主要是通过Proxy的newProxyInstance()方法根据传入的对象参数为这个对象创建一个符合某一接口的代理对象Proxy
然后通过把这个对象传给Invocationhandler接口中的方法Invoke(),通过反射机制调用目标类的代码。
如下所示:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class jdkproxy implements InvocationHandler{
private Object tar; //需要被代理的目标对象
public Object createInstance(Object tar){
this.tar = tar;
/*
* 第一个参数设置用哪个类加载器去加载代理对象,一般采用跟目标类相同的类装载器
* 第二个参数设置动态代理类需要实现的接口
* 第三个参数设置回调对象,动态代理方法在执行时,会调用this里面的invoke方法去执行
*/
return Proxy.newProxyInstance(this.tar.getClass().getClassLoader(), this.tar.getClass().getInterfaces(), this);
}
/*
* 第一个参数proxy就是代理对象,newProxyInstance方法的返回对象
* 第二个参数method设置调用的方法
* 第三个参数args设置方法中的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----------------BEFORE------------------");
Object invoke = method.invoke(tar, args);
System.out.println("----------------AFTER-------------------");
return invoke;
}
}
编写一个测试接口:
public interface testInter {
public void p();
}
接口的实现类:
public class testImpl implements testInter {
public void p(){
System.out.print("test\n");
}
}
测试jdk代理:
public class testtas {
public static void main(String[] args) {
jdkproxy pr = new jdkproxy();
testInter tI = new testImpl();
testInter ptI = (testInter)pr.createInstance(tI);
ptI.p();
}
}
测试结果:
基于CGlib的动态代理
JDK代理只能为接口创建代理实例,对于没有实现接口类但是需要被代理的对象来说,可以选着spring支持的另一种代理即CGLIB代理。spring中如果一个业务对象并没 有实现一个接口,默认就会使用CGLIB。
CGLib采用底层字节码技术,可以为一个类创建子类,并在子 类中采用方法拦截技术拦截所有父类方法的调用,从而达到代理的目的。
CGLIB代理类通过实现MethodInterceptor接口,在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。
如下所示:
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class cglibproxy implements MethodInterceptor{
private Object tar; //需要被代理的目标对象
public Object create(Object tar){
this.tar = tar;
Enhancer enhancer = new Enhancer(); //生成代理对象
enhancer.setSuperclass(this.tar.getClass()); //设置目标类为代理对象的父类
enhancer.setCallback(this); //设置回调对象为本身
return enhancer.create(); //返回代理类对象
}
/*
* 第一个参数是CGLib动态生成生成一个代理类对象(creat(object tar)生成的对象)
* 第二个参数是设置目标对象方法 (目标类所调用的被代理的方法引用)
* 第三个参数是设置目标对象方法的参数
* 第四个参数是生成的代理类对方法的代理引用
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//在代理真实对象方法执行前执行一些操作
System.out.println("----------------BEFORE------------------");
Object invoke = methodProxy.invoke(this.tar, args);
//在代理真实对象方法执行后执行一些操作
System.out.println("----------------AFTER------------------");
return invoke;
}
}
编写测试类(无需接口实现接口):
public class TestAttibuteSet {
public void test(){
System.out.println("testCGLib");
}
}
编写CGLib代理测试:
public class testtas {
public static void main(String[] args) {
cglibproxy cgp = new cglibproxy();
TestAttibuteSet ts = new TestAttibuteSet();
TestAttibuteSet tc = (TestAttibuteSet)cgp.create(ts);
tc.test();
}
}
测试输出:
注:在拦截器里面, @Autowired 和 @Resource是不生效的。