动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理
在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。
基于jdk的动态代理的实例:
2.1 Student.java 接口类
package com.xidian.proxy;
public interface Student {
public void login();
public void submit();
}
2.2 StudentImpl.java 实现类
package com.xidian.proxy;
public class StudentImp implements Student {
@Override
public void login() {
System.out.println("登录");
}
@Override
public void submit() {
System.out.println("提交");
}
}
2.3 MyProxy.java 代理类:
package com.xidian.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//cjlib的代理是基于继承实现的,jdk是基于接口实现的代理
public class MyProxy implements InvocationHandler{
private Object targetObject;
public Object createProxyInstance(Object targetObject)
{
this.targetObject = targetObject;
/*
* public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
* InvocationHandler h)
* 第一个参数是要代理对象的类加载器
* 第二个参数是要代理类的接口
* 第三个参数是InvocationHandler的实现类实例,即就是MyProxy 即this
*/
return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),
this.targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验");
method.invoke(targetObject, args);//执行被代理target对象的方法
System.out.println("日志记录");
return null;
}
}
2.4 测试类
package com.xidian.proxy;
import org.junit.Test;
public class testProxy {
@Test
public void jdkProxy(){
MyProxy myProxy = new MyProxy();
Student proxy = (Student)myProxy.createProxyInstance(new StudentImp());
proxy.login();
proxy.submit();
}
}
CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。
基于cglib的动态代理的实例:
3.1 ClassHasNoInterface.java 实现类:
package com.xidian.CGlib;
public class ClassHasNoInterface {
public void method(){
System.out.println("方法一执行");
}
public void function(){
System.out.println("方法二执行");
}
}
3.2 测试类:
public class testCGLib {
@Test
public void test1() {
final ClassHasNoInterface p = new ClassHasNoInterface();
//返回p的动态代理对象:该代理对象是Person的子类
ClassHasNoInterface pp = (ClassHasNoInterface)Enhancer.create(p.getClass(), new MethodInterceptor(){
@Override
public Object intercept(Object proxy, Method method, Object[] arg2,
MethodProxy arg3) throws Throwable {
long time = System.nanoTime();//纳秒 1毫秒=1000纳秒
Object obj = method.invoke(p, arg2);
System.out.println(method.getName()+"运行耗时:"+(System.nanoTime()-time)+"纳秒");
return obj;
}
});
pp.method();
pp.function();
}
原理区别:
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换