Spring番外篇-ProxyFactory

1. 为什么使用ProxyFactory

使用Spring的ProxyFactory对比Jdk的Proxy创建静态代理有什么好处?

  1. Jdk的Proxy只支持接口级别的代理;假设类没有实现任何接口时,则需要引入Cglib的库,使用Cglib创建代理
  2. 而Spring的ProxyFactory整合了Jdk的ProxyCglib,使得我们可以使用统一的api来创建代理对象

2. 前置知识-Advice

Advice

  • 对被代理对象的增强

常见的三大实现

  • BeforeAdvice: 在被代理对象方法执行执行
  • AfterAdvice: 在被代理对象方法执行执行
  • MethodInterceptor: 在被代理对象方法执行前后执行 ( 最常用
    在这里插入图片描述
    接下来我们使用ProxyFactory创建代理时,就会使用MethodInterceptor

注:Spring创建代理时,最常用的Aspect也是MethodInterceptor
例如在使用注解@Aspect创建代理时:给增强类标注@Aspect注解,最终该增强类就会被封装成MethodInterceptor

MethodInterceptor签名
在这里插入图片描述

3. 前置知识-Advisor

Advisor = Advice + 切入点

  • Advice 具体的增强逻辑
  • 切入点 匹配需要被增强的类或方法

常见的两大实现

在这里插入图片描述

  • IntroductionAdvisor: 可以基于判断是否进行切入
  • PointcutAdvisor: 可以基于方法判断是否进行切入 ( 最常用 )

注:Spring创建代理时,最常用的Advisor就是PointcutAdvisor
例如在使用注解@Pointcut创建代理时:给类标注@Pointcut注解,在注解内指定表达式,最终该类就会被封装成PointcutAdvisor

4. 使用ProxyFactory创建静态代理

被代理类定义如下

    public class Person {

        private final String name;

        private Person(String name) {
            this.name = name;
        }

        public void sayHello(String otherName) {
            System.out.printf("hello : %s , i'm : %s %n", otherName, this.name);
        }

        public String personName() {
            return "name = " + this.name;
        }


    }

4.1 基于Advice创建代理

    @Test
    public void create_proxy_advice() throws Exception {

        ProxyFactory proxyFactory = new ProxyFactory();

        // 1. 设置被代理的对象
        proxyFactory.setTarget(new Person("zzzj"));

        // 2. 添加增强 ( Advice ) 逻辑
        proxyFactory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {

                // Before
                System.out.printf("Before execute : %s , args = %s %n", invocation.getMethod().getName(), Arrays.toString(invocation.getArguments()));
                // 执行方法
                Object result = invocation.proceed();

                // After
                System.out.printf("After execute : %s , result = %s %n", invocation.getMethod().getName(), result);

                return result;
            }
        });

        // 3. 创建代理对象
        Person proxied = (Person) proxyFactory.getProxy();

        proxied.sayHello("Xiao Hong");

    }

输出结果

Before execute : sayHello , args = [Xiao Hong] 
hello : Xiao Hong , i'm : zzzj 
After execute : sayHello , result = null 

4.2 基于Advisor创建代理

    @Test
    public void create_proxy_advisor() throws Exception {
        ProxyFactory proxyFactory = new ProxyFactory();

        // 1. 设置被代理的对象
        proxyFactory.setTarget(new Person("zzzj"));

        // 2. 创建增强 ( Advice )
        Advice advice = new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                // Before
                System.out.printf("Before execute : %s , args = %s %n", invocation.getMethod().getName(), Arrays.toString(invocation.getArguments()));

                // 执行方法
                Object result = invocation.proceed();

                // After
                System.out.printf("After execute : %s , result = %s %n", invocation.getMethod().getName(), result);

                return result;
            }
        };

        // 3. 创建 ( Advisor )

        // 3.1 赋值 { advice } 给 { StaticMethodMatcherPointcutAdvisor }

        // 3.2 { StaticMethodMatcherPointcutAdvisor } 是 { PointcutAdvisor }的实现类
        Advisor advisor = new StaticMethodMatcherPointcutAdvisor(advice) {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {

                // 仅匹配personName方法
                return method.getName().equalsIgnoreCase("personName");
            }
        };

        // 3.3 添加Advisor
        proxyFactory.addAdvisor(advisor);

        // 4. 创建代理对象
        Person proxied = (Person) proxyFactory.getProxy();

        // 4.1 调用sayHello()
        proxied.sayHello("Xiao Ming");

        // 4.2 调用personName()
        proxied.personName();

    }
hello : Xiao Ming , i'm : zzzj 

Before execute : personName , args = [] 
After execute : personName , result = name = zzzj 

根据输出结果可以发现,sayHello()方法并没有被增强,personName()方法得到了增强

4.3 ProxyFactory的常用属性:exposeProxy

在代理对象执行方法时,通过this.xxxMethod()调用其他方法时,xxxMethod()并不会被增强
原因是this指向的未被代理的对象

如果希望在当前方法中拿到被增强后的对象,可以借助SpringAopContext#currentProxy

只有给ProxyFactoryexposeProxy属性设置为true时 ( 默认为false ):AopContext#currentProxy才能被使用

public class AopContextTests {

    @Test
    public void expose_tests() throws Exception {

        ProxyFactory proxyFactory = new ProxyFactory(new AopContextTests());

        // 1. 设置ExposeProxy为true
        proxyFactory.setExposeProxy(true);

        // 2. 设置 { Advice } : Advice什么也没有做, 直接执行了方法
        proxyFactory.addAdvice((MethodInterceptor) MethodInvocation::proceed);

        // 3. 创建代理
        AopContextTests proxy = (AopContextTests) proxyFactory.getProxy();

        // 4. 调用printThis
        proxy.printThis();

        // 5. 调用printCurrentProxy()
        proxy.printCurrentProxy();

    }

    void printThis() {
        System.out.println("this = " + this.getClass().getName());
    }

    void printCurrentProxy() {
        System.out.println("currentProxy = " + AopContext.currentProxy().getClass().getName());
    }

}

输出结果

this = com.zzzj.spring.aop.AopContextTests
currentProxy = com.zzzj.spring.aop.AopContextTests$$EnhancerBySpringCGLIB$$6003f0a6

4.4 强制转换为Advised

通过ProxyFactory创建出来的代理对象,Spring都会为其实现Advised接口
将被代理对象转换为Advised对象后,可以动态得增加、删除、替换Advisor

    @Test
    public void cast_to_advised() throws Exception {

        ProxyFactory proxyFactory = new ProxyFactory();

        // 1. 设置被代理的对象
        proxyFactory.setTarget(new Person("zzzj"));

        // 2. 添加增强 ( Advice ) 逻辑
        proxyFactory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {

                // Before
                System.out.printf("Before111 execute : %s , args = %s %n", invocation.getMethod().getName(), Arrays.toString(invocation.getArguments()));
                // 执行方法
                Object result = invocation.proceed();

                // After
                System.out.printf("After111 execute : %s , result = %s %n", invocation.getMethod().getName(), result);

                return result;
            }
        });

        // 3. 创建代理对象
        Person proxied = (Person) proxyFactory.getProxy();

        proxied.sayHello("Xiao Hong");

        System.out.println("==================================================");

        // 4. 强制转换为 { Advised } 类型
        Advised advised = (Advised) proxied;

        // 删除第一个Advisor
        advised.removeAdvisor(0);

        // 添加
        // advised.addAdvice();

        // 移除
        // advised.removeAdvice()

        // 替换
        // advised.replaceAdvisor()

        proxied.sayHello("Xiao Ming");
    }

输出结果

Before111 execute : sayHello , args = [Xiao Hong] 
hello : Xiao Hong , i'm : zzzj 
After111 execute : sayHello , result = null 
==================================================
hello : Xiao Ming , i'm : zzzj 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值