java 动态代理
动态代理
代理功能就是在调用目标对象时并不直接调用目标,而是调用代理对象,再由代理对象调用目标方法。这样在完成目标功能之外还可以增强其他功能。
JDK 动态代理
创建代理使用代理类 java.lang.reflect.Proxy
,只需要实现newProxyInstance
方法。此方法要求目标对象必须实现了某个接口。
public class ProxyFactory {
// 维护目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// 生成代理对象
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 指定当前目标对象使用类加载器
target.getClass().getInterfaces(), // 目标对象实现的接口的类型,使用泛型方式确认类型
new InvocationHandler() { // 事件处理,将要执行的方法和参数传入
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("操作目标对象前");
Object retValue = method.invoke(target, args);
System.out.println("操作目标对象后");
return retValue;
}
}
);
}
}
public static void main(String[] args) {
// 创建原始的目标对象
List<Object> list = new ArrayList<>();
// 为目标对象创建代理类
list = (List<Object>) new ProxyFactory(list).getProxyInstance();
// 操作目标对象时通过代理对象间接操作
list.add("123");
System.out.println(list);
list.clear();
System.out.println(list);
}
Cglib 动态代理
如果目标对象没有实现接口,则可以通过以目标对象子类的方式实现代理。Cglib代理也叫子类代理,它是在内存中构建一个子类对象从而实现对目标功能的拓展。需要引入Cglib对应的jar包。
注意:
- 代理的类不能为 final
- 代理对象的方法如果为 final static,那么不会被拦截并创建额外的方法
public class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
@Override
public Object intercept(Object o,
Method method,
Object[] args,
MethodProxy methodProxy) throws Throwable {
// 前置操作
System.out.println("before");
// 调用目标对象
Object returnValue = method.invoke(target, args);
// 后置操作
System.out.println("after");
return returnValue;
}
public Object getProxyInstance() {
// 创建工具类
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(target.getClass());
// 设置回调函数
enhancer.setCallback(this);
// 创建子类/代理类
return enhancer.create();
}
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
list = (List<Object>) new ProxyFactory(list).getProxyInstance();
list.add("123");
System.out.println(list);
list.clear();
System.out.println(list);
}
}
Spring 的 AOP 操作
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理