JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,与cglib不同,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
默认状态下,Spring-AOP默认使用JDK动态代理,当需要代理的对象没有实现任何接口时,才使用cglib动态代理。cglib动态代理创建代理实例速度慢,但是运行速度快;JDK动态代理创建实例速度快,但是运行速度慢。如果实例是单例的,推荐使用cglib方式动态代理,反之则使用JDK方式进行动态代理。Spring的实例默认是单例,所以这时候使用cglib性能高。
1.先写个接口
public interface Person {
void run();
String talk(String word);
}
2.实现接口
public class Man implements Person {
@Override
public void run() {
System.out.println("Man is running..");
}
@Override
public String talk(String word) {
System.out.println("man is talking:");
return word;
}
}
3.JDK代理实现:
public class JDKProxy implements InvocationHandler {
private Object targetObject;//需要被代理的对象
public JDKProxy() {
}
/***
* 获取代理对象
* @param o 需要被代理的对象
* @return 代理后的对象
*/
public Object getProxyObject(Object o){
this.targetObject = o;
return Proxy.newProxyInstance(o.getClass().getClassLoader(),//ClassLoader loader:类加载器,定义了由哪个ClassLoader对象来生成代理对象进行加载
o.getClass().getInterfaces(),//Class<?>[] interfaces:得到该对象实现全部的接口,这样便可以调用所有接口内的方法了。
this::invoke);//InvocationHandler h:调用处理器,它是得到InvocationHandler接口的子类实例
}
/***
*
* @param proxy 代理对象,也就是Proxy.newProxyInstance()方法返回的对象,通常我们用不上它
* @param method 表示当前被调用方法的反射对象
* @param args 表示当前被调用方法的参数,当然如果这个调用是没有参数的,那么args是一个零长数组
* @return 最后要说的是invoke()方法的返回值为Object类型,它表示当前被调用的方法的返回值,如果没有返回值的,invoke()返回的就必须是null了。
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result=null;
System.out.println("Proxy start...");
System.out.println("method name:"+method.getName());
//执行前的逻辑
result=method.invoke(targetObject, args);
//执行后的逻辑
System.out.println("Proxy end...");
return result;
}
}
cglib代理实现
public class CGLibProxy implements MethodInterceptor {
private Object targetObject;//需要被代理的对象
/***
* 获取代理对象
* @param obj 需要被代理的对象
* @return 代理后的对象
*/
public Object getProxyObject(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
// 返回代理对象
return proxyObj;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
Object result=null;
System.out.println("Proxy start...");
System.out.println("method name:"+method.getName());
//执行前的逻辑
result=method.invoke(targetObject, args);
//执行后的逻辑
System.out.println("Proxy end...");
return result;
}
}
4.测试类
public static void main(String[]args){
Person manProxy=(Person)(new JDKProxy().getProxyObject(new Man()));
manProxy.run();
String talkStr= manProxy.talk("hello world");
System.out.println(talkStr);
}
DK代理是不需要第三方库支持,只需要JDK环境就可以进行代理,在使用cglib动态代理时,需要引入cglib的jar包,有两种方式,一是引入cglib.jar和asm.jar,二是引入cglib-nodep.jar