使用ProxyFactoryBean实现AOP

代理的原始生成办法

以前我在springAOP里写过aspectJ的代理生成逻辑,也看了spring编码方式的代理生成。我们可以来复习一下。

我们整一个接口和实现类:

public interface MyService2 {

    void myMethod2();
}


@Service
public class MyServiceImpl2 implements MyService2 {
    @Override
    public void myMethod2() {
        System.out.println("myMethod2 invoked...");
    }
}

再整一个拦截器,或者叫Advice,就是说,切面怎么切的意思。他接受一个JoinPoint作为参数,在这里就是MethodInvocation(一次方法调用)。

@Component
public class MyAdvisor2 implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("before invoke " + invocation.getMethod().getName());
        invocation.proceed();
        System.out.println("after invoke " + invocation.getMethod().getName());

        return null;
    }
}

然后是配置类:

@Configuration
@ComponentScan("com.ocean.spring.aop.useProxyFactory")
public class ConfigOfAop2 {

    @Bean("myProxyFactory")
    @Lazy
    public ProxyFactory proxyFactory(MyService2 myService2,
                                     MyAdvisor2 myAdvisor2) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(myService2);
        proxyFactory.addAdvice(myAdvisor2);
        return proxyFactory;
    }
}

测试类:

public class AopTest2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigOfAop2.class);
        ProxyFactory proxyFactory = context.getBean("myProxyFactory", ProxyFactory.class);
        MyService2 proxy = (MyService2)proxyFactory.getProxy();
        proxy.myMethod2();
    }
}

从这个demo中我们已经可以看到spring的aop全貌了:代理的接口,目标对象,如何代理,以及使用代理工厂去生成代理。


使用ProxyFactoryBean实现AOP

我们还能够使用ProxyFactoryBean去生成代理,这时候就不再是原始的生成方式了,因为这时需要走spring的bean的生命周期。

在这里插入图片描述

他首先是个FactoryBean,那么今后将使用

@Nullable
	T getObject() throws Exception;

去获取对象。

然后他是个BeanClassLoaderAware, BeanFactoryAware,所以会在这个对象初始化的时候获取到加载spring的类加载器以及spring的BeanFactory

在这里插入图片描述

他又是个ProxyCreatorSupport,所以本质上也是个aop的配置类,在创建aop代理的时候一定会将this传进去。

分析到这里,我们看看新的demo。

同样还是一个被代理的接口和目标方法:

public interface MyService {

    void myMethod();
}
@Service("myService")
public class MyServiceImpl implements MyService {
    @Override
    public void myMethod() {
        System.out.println("myMethod invoked...");
    }
}

然后是如何代理:

@Component
public class MyAdvisor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("before invoke " + invocation.getMethod().getName());
        invocation.proceed();
        System.out.println("after invoke " + invocation.getMethod().getName());

        return null;
    }
}

配置类:

@Configuration
@ComponentScan("com.ocean.spring.aop.use_proxyFactoryBean")
public class ConfigOfAop {

    @Bean
    public ProxyFactoryBean proxyFactoryBean() throws ClassNotFoundException {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setProxyInterfaces(new Class[]{MyService.class});
        proxyFactoryBean.setInterceptorNames("myAdvisor");
        proxyFactoryBean.setTargetName("myService");
        return proxyFactoryBean;
    }
}

测试类:

public class AopTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigOfAop.class);
        MyService myService = context.getBean("proxyFactoryBean", MyService.class);
        myService.myMethod();
    }
}

测试结果没什么好说的。这里的关键是:

 MyService myService = context.getBean("proxyFactoryBean", MyService.class);

我要获取的是proxyFactoryBean,但为什么拿到的是MyService类型的?

我们先不急类型转换,先看看原生的是什么对象:

在这里插入图片描述

他是一个MyService的一个代理对象,因此可以转成MyService类型。现在我们需要debug看看生成代理的过程。

在这里插入图片描述
在这里插入图片描述
proxyFactoryBean对象在spring初始化的时候已经创建了,所以我们能够在ioc容器中取出。

在这里插入图片描述
如果不是FactoryBean的,就直接打回去了。

在这里插入图片描述

在这里插入图片描述

去获取里面的对象。

在这里插入图片描述

终于到了getObject()了。

在这里插入图片描述

从容器中取出拦截器,然后做成一个Advisor添加到advisor列表中(Advisor可以看成是AdvicePointcut的联合):

在这里插入图片描述
在这里插入图片描述
Advisor链初始化后,就开始要获取代理了。

在这里插入图片描述
然后他又去ioc容器获取目标对象给targetSource赋值。现在终于做好准备(所有的配置都准备好了)去生成代理了。

在这里插入图片描述

的确是把this作为配置类传进去了。

在这里插入图片描述

把配置丢给jdk动态代理。

在这里插入图片描述
最后生成代理的部分就是jdk的内容了。

debug的问题

idea来debug的时候,出现了大量的toString方法,而我们其实只有红框里面的三句是要打印的:

在这里插入图片描述
这时候我们做个设置即可(关掉红框的选项):

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值