Interview preparation — SpringAop

  • Post author:
  • Post category:其他




动态代理
  • 动态代理可以正对一些不特定的


JDK自带的动态代理
  • JDK中 java.lang.reflect 包下的Proxy类是Java构造代理类的入口,其中方法newProxyInstance是创建代理对象的方法,方法源码如下:
  • 通过Proxy动态代理获得一个代理对象,在代理对象中对某个方法进行增强
 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
    {}
    // ClassLoader loader : 被代理的对的类加载器
    // Class<?>[] interfaces:被代理对象所施行的所有接口
    // InvocationHandler h:只相信处理器对象,专门用来定义增强的规则
  
  • 在InvocationHandler中是我们实现增强逻辑的地方,其中有一个invoke方法是我们自实现的逻辑
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
//Object proxy: 需要代理的对象
//Method method:被代理的方法
//Object[] args:被代理方法运行时的实参


Demo
public interface Person {
    public void eat(String name);
    public void drink();
}
public class Dog implements Person {
    @Override
    public void eat(String name) {
        System.out.println("dog eat " + name);
    }

    @Override
    public void drink() {
        System.out.println("dog drink kele");
    }
}

public class MyProxy {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Class[] interfaces = dog.getClass().getInterfaces();
        Person proxyPersion = (Person)Proxy.newProxyInstance(dog.getClass().getClassLoader(), interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("洗手");
                Object obj =  method.invoke(dog, args);
                System.out.println("洗头");
                return obj;
            }
        });
        proxyPersion.eat("面包");
    }
}


JDK动态代理总结
  • 在不修改原有代码,或者无法修改原有代码的情况下,增强对象功能,使用代理对象代替原来的对象去完成功能而达到扩展功能的目的。

  • JDK动态代理的局限性

  • 一定要有接口和实现类的存在

  • 增强接口中定义的方法,实现类中其他和接口无关的方法是无法增强的

  • 只能读取到接口方法上的注解,不能读取到实现类方法上的注解

  • 总而言之,JDK动态代理只能和接口打交道,不能与具体实现类有交集,因为他并不知道所要代理的类是那个实现类



CGLib 动态代理
  • demo
/**
 * Created by jiamin5 on 2023/3/12.
 */
public class TestCglib {
    public static void main(String[] args) {
        TestCglib testCglib = new TestCglib();
        testCglib.testCglin();
    }
    public void testCglin(){
        //获取一个person的代理对象
        Person person = new Person();
        //获取一个Enhancer 对象
        Enhancer enhancer = new Enhancer();
        //设置父类字节码
        enhancer.setSuperclass(person.getClass());
        //获取MethodInterceptor
        MethodInterceptor methodInterceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
               // Object obj :生成之后的代理对象personProxy
                // Method method:父类中原本要执行的方法 Persion >>> eat()
                // Object[] args:方法在调用时候传入的实参数
                // MethodProxy proxy:子类中重写父类的方法personProxy >>> eat();
                Object res = null;
                if(method.getName().equals("eat")){
                    System.out.println("洗手");
                    res = proxy.invokeSuper(obj, args);
                    System.out.println("刷网");
                }
                return res;
            }
        };
        //设置回调函数:methodInterceptor
        enhancer.setCallback(methodInterceptor);
        //获得代理对象
        Person personProxy = (Person) enhancer.create();
        //使用代理对象完成功能
        personProxy.eat("面包");
    }

    static class Person{
        public Person(){}
        public void eat(String foodName){
            System.out.println("eat some 面包 和" + foodName);
        }
    }
}
  • CGLib 动态代理

    • 面向父类的,和接口没有直接关系
    • 不仅仅可以增强接口中定义的方法,也可以增强类中的其他方法
    • 可以读取父类中方法上所有注解

      在这里插入图片描述
  • 以上Son是由于CGLib生成的一个子类实现,我们在子类中增加了增强逻辑。



版权声明:本文为liaojiamin0102原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。