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包。

注意:

  1. 代理的类不能为 final
  2. 代理对象的方法如果为 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代理

posted @ 2022-05-02 13:04  某某人8265  阅读(28)  评论(0编辑  收藏  举报