静态代理与动态代理
相同:AOP、都可以用来做增强
静态代理
动态代理有两种-JDK动态代理和CGLIB动态代理
spring会使用哪种代理方式呢?
1、如果代理目标对象实现了接口,那么会默认使用jdk动态代理,代理对象是接口也可以设置强制使用cglib代理方式,如果代理目标对象只是一个普通对象,并没有实现接口,那么会使用CGLIB代理
为什么jdk代理基于接口实现?
因为在jdk代理中,获取代理目标对象的方法是通过使用Object.getClass.getInteface方法来生成代理实例对象
而,cglib代理则是通过增强器来设置代理类,获取到对象
JDK代理不需要依赖第三方的库,只要安装了JDK环境就可以进行代理,代理实现逻辑:
实现InvocationHandler接口,重写invoke()
使用Proxy.newProxyInstance()产生代理对象,方法入参【ClassLoader loader, Class<>[] interfaces, InvocationHandler h】
要求:被代理的对象必须要实现接口
CGLib 必须依赖于CGLib的类库,代理实现逻辑:
实现MethodInterceptor接口,重写intercept()
使用Enhancer对象.create()产生代理对象
JDK动态代理:
基于接口实现
实现的是InvocationHandler接口,重写invoke方法,增强操作就在这个方法里面做,对外提供一个获取代理对象的方法。
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 基于接口的jdk动态代理
*/
@Slf4j
public class DynamicProxyInterface implements InvocationHandler {
private Object obj;
/**
* @description: 传入目标对象,获取代理对象
*/
public Object getProxyObj(Object target) {
obj = target;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
/**
* @description: 目标对象的方法被调用的时候,可以加入增强处理
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//目标对象的方法被调用之前的增强处理,doSomething
log.info(method.getName());
Object o = method.invoke(obj, args);
//目标对象的方法被调用之后的增强处理,doSomething
log.info(method.getName());
return o;
}
//测试
public static void main(String[] args) {
UserService userService = new UserService();
TestJDKAOP testJDKAOP = new TestJDKAOP();
UserService userServiceProxy = (UserService) testJDKAOP.getProxyObj(userService);
//代理对象,调用对象里的方法都会执行invoke里面的增强操作
userServiceProxy.getUserInfo()
}
}
CGLIB动态代理
CGLib使用一个增强器Enhancer,设置传入的代理对象类型,enhancer有一个拦截方法(回调函数)setCallback,在此方法内部回调实现了MethodInterceptor接口的类,类里面做增强逻辑
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author Administrator
*/
@Slf4j
public class DynamicProxyCglib {
/**
* @description: 传入目标对象的类型,获取代理对象
*/
public Object getProxyObject(Class<?> clazz) {
//定义字节码增强器
Enhancer enhancer = new Enhancer();
//通过增强器设置代理对象的类型
enhancer.setSuperclass(clazz);
//给增强器设置回调函数
//方法的拦截器、此处直接用lambda直接实现MethodInterceptor
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
//目标对象的方法被调用之前的增强处理,doSomething
log.info(method.getName());
//目标对象的方法被调用,此处必须使用methodProxy.invokeSuper,防止被拦截器循环拦截
Object invoke = methodProxy.invokeSuper(o, objects);
//目标对象的方法被调用之后的增强处理,doSomething
log.info(method.getName());
return invoke;
});
//执行增强器,返回代理对象
return enhancer.create();
}
}
//测试
public static void main(String[] args) {
NeedToProxyObject needOject = new NeedToProxyObject();
//使用cglib获取代理对象(入参为class)
DynamicProxyCglib dpc = new DynamicProxyCglib();
NeedToProxyObject proxyObject = (NeedToProxyObject)dpc.getProxyObject(NeedToProxyObject.class);
//调用对象方法
...
}