使用ProxyFactoryBean实现AOP

news/2024/7/6 6:30:46 标签: java, 代理模式, spring

使用ProxyFactoryBean实现AOP

      • 代理的原始生成办法
      • 使用ProxyFactoryBean实现AOP
      • debug的问题

代理的原始生成办法

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

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

java">public interface MyService2 {

    void myMethod2();
}


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

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

java">@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;
    }
}

然后是配置类:

java">@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;
    }
}

测试类:

java">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,那么今后将使用

java">@Nullable
	T getObject() throws Exception;

去获取对象。

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

在这里插入图片描述

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

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

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

java">public interface MyService {

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

然后是如何代理:

java">@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;
    }
}

配置类:

java">@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;
    }
}

测试类:

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

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

java"> 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方法,而我们其实只有红框里面的三句是要打印的:

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

在这里插入图片描述


http://www.niftyadmin.cn/n/1311915.html

相关文章

Java IO流的复制操作

复制. import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;class Main {public static void main(String[] args) throws IOException {int k 0;FileOutputStream fo new FileOutputStre…

chmod 777命令_Linux 命令(二)

开关机sync :把内存中的数据写到磁盘中(关机、重启前都需先执行sync)shutdown -r now或reboot :立刻重启shutdown -h now :立刻关机shutdown -h 20:00 :预定时间关闭系统(晚上8点关机,如果现在超过8点,则明…

spark对接elasticsearch遇到的坑

spark对接elasticsearch遇到的坑环境Provider org.apache.hadoop.hdfs.DistributedFileSystem could not be instantiatedERROR NetworkClient: Node [xxx] failed (java.net.SocketException: Connection reset); selected next node [xxx]Cannot parse value [2020-04-19 09:…

c++ char字符相等比较_【算法】高效quot;KMPquot;字符匹配算法就这么简单

1、聊一聊今天跟大家推荐的是一首重量级的钢琴曲中文名为《克罗地亚狂想曲》,一般人听这个曲子可能觉得比较亢奋,如果大家了解一下克罗地亚战争就会发现其实它是如此的悲伤。本篇文章如约而至,很多小伙伴在理解KMP字符匹配算法有点难度&#…

自己用的停用词(2955个)

停用词多就是好啊,先记下来,以后增加的话再增 、 老 有时 以前 。 一下 要不然 ── 者 dont 〈 等到 反过来说 〉 一一 《 》 古来 your 准备 往往 而 「 」 怎 挨个 without 『 』 【 these ‐ 】 逐渐 再者 – — would 〔 就是 怕 ― 〕 ‖ 〖 甚至 …

推荐系统的基础算法和企业级设计

推荐系统的基础算法和企业级设计推荐系统介绍推荐系统的技术选型和基础数据技术选取数据简介算法讨论基于统计学的推荐算法LFM算法实时推荐算法项目模块简介推荐系统介绍 在互联网时代,为了能够给用户良好的体验并且增大用户的留存率,推荐系统应运而生。…

python算法是指_python 算法

算法的复杂度 算法的时间复杂度是指算法需要消耗的时间资源 时间复杂度用“O(数量级)”来表示 常见的时间复杂度有: O(1)常数阶; 问题规模越大效率越高,时间不变, a [1,2,3] a[0]=1&#xff0c…

考试很可能考的

void move(ElemType A[] ,int len) {int i0,jlen-1; //i表示左端偶数元素的下标&#xff0c;j表示右端奇数元素的下标while(i<j) {while(i<j&&A[i]%2!0) i; //从前向后找到一个偶数元素while(i<j&&A[j]%2!1) j--; //从后向前找到一个奇数元素i…