这里的自动代理,我讲的是自动代理bean对象,其实就是在xml中让我们不用配置代理工厂,也就是不用配置class为org.springframework.aop.framework.ProxyFactoryBean的bean。
总结了一下自己目前所学的知识。
发现有三种方式实现自动代理
用Spring一个自动代理类DefaultAdvisorAutoProxyCreator:
1
|
< bean class = "org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" data-filtered = "filtered" ></ bean >
|
例如:
原来不用自动代理的配置文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<!--?xml version="1.0" encoding="UTF-8"?-->
< beans xmlns = "https://www.springframework.org/schema/beans" xmlns:context = "https://www.springframework.org/schema/context" xmlns:tx = "https://www.springframework.org/schema/tx" xmlns:xsi = "https://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.3.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.3.xsd
https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 代理前原对象 -->
< bean class = "cn.hncu.xmlImpl.Person" id = "person" ></ bean >
<!-- 切面 = 切点+通知 -->
< bean class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" id = "advisor" >
<!-- 切点 -->
< property name = "patterns" >
< list >
< value >.*run.*</ value >
</ list >
</ property >
<!-- 通知-由我们写,实际代理动作 -->
< property name = "advice" >
< bean class = "cn.hncu.xmlImpl.AroundAdvice" id = "advice" ></ bean >
</ property >
</ bean >
<!-- 代理工厂 -->
< bean class = "org.springframework.aop.framework.ProxyFactoryBean" id = "personProxied" >
<!-- 放入原型对象 -->
< property name = "target" ref = "person" ></ property >
<!-- 放入切面 -->
< property name = "interceptorNames" >
< list >
< value >advisor</ value >
</ list >
</ property >
</ bean >
</ beans >
|
现在改用自动代理,如下配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
< beans ... = "" >
<!-- 代理前原对象 -->
< bean class = "cn.hncu.xmlImpl.Person" id = "person" ></ bean >
<!-- 切面 = 切点+通知 -->
< bean class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" id = "advisor" >
<!-- 切点 -->
< property name = "patterns" >
< list >
< value >.*run.*</ value >
</ list >
</ property >
<!-- 通知-由我们写,实际代理动作 -->
< property name = "advice" >
< bean class = "cn.hncu.xmlImpl.AroundAdvice" id = "advice" ></ bean >
</ property >
</ bean >
<!-- 自动代理 -->
< bean class = "org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" ></ bean >
</ beans >
|
测试方法
1
2
3
4
5
6
7
8
|
@Test //自动代理
public void demo4(){
ApplicationContext ctx = new ClassPathXmlApplicationContext( "cn/hncu/xmlImpl/4.xml" );
//我们直接在这里获取Person对象就可以了,因为在最开始xml文件newPerson对象后,Spring就已经帮我们代理了!
Person p =ctx.getBean(Person. class );
p.run();
p.say();
}
|
相对于前面,也就是把代理工厂部分换成自动代理了。
演示结果:
自己写一个自动代理底层实现:
我们也可以写一个类,来实现DefaultAdvisorAutoProxyCreator自动代理的功能!
首先,我们需要实现一个接口,也就是BeanPostProcessor接口。
BeanPostProcessor接口作用是:如果我们需要在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。
而我们想要在原型对象bean被创建之后就代理了,就必须在原来的容器中拿到原来的原型对象,需要拿到原来spring容器中的切面对象,这个时候,我们就需要原来的容器,这个时候就需要另一个接口,也就是ApplicationContextAware接口!
通过这2个接口,我们就可以实现自动代理了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
package cn.hncu.xmlImpl;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class MyAutoProxy implements BeanPostProcessor,ApplicationContextAware{
private ApplicationContext applicationContext= null ;
//bean创建之前调用
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean; //在这里,我们直接放行
}
//bean创建之后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
ProxyFactoryBean factory = new ProxyFactoryBean();
//把原型对象放入代理工厂
factory.setTarget(bean);
//在这里
Advisor adv = applicationContext.getBean(Advisor. class );
factory.addAdvisor(adv);
//返回被代理后的对象
return factory.getObject();
}
//拿到原来的spring中的容器
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this .applicationContext=applicationContext;
}
}
|
5.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
< beans... >
<!-- 代理前原对象 -->
< bean class = "cn.hncu.xmlImpl.Person" id = "person" ></ bean >
<!-- 切面 = 切点+通知 -->
< bean class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" id = "advisor" >
<!-- 切点 -->
< property name = "patterns" >
< list >
< value >.*run.*</ value >
</ list >
</ property >
<!-- 通知-由我们写,实际代理动作 -->
< property name = "advice" >
< bean class = "cn.hncu.xmlImpl.AroundAdvice" id = "advice" ></ bean >
</ property >
</ bean >
<!-- 自己写的自动代理 -->
< bean class = "cn.hncu.xmlImpl.MyAutoProxy" ></ bean >
</ beans... >
|
测试方法:
1
2
3
4
5
6
7
|
@Test //自己实现的自动代理
public void demo5(){
ApplicationContext ctx = new ClassPathXmlApplicationContext( "cn/hncu/xmlImpl/5.xml" );
Person p =ctx.getBean(Person. class );
p.run();
p.say();
}
|
测试结果就不上图了,和前面是一样的。
其实很多时候,我们如果自己去练一下底层,对上层的框架更好理解。
还有一种方法。
使用aop标签配自动代理
需要在beans加一个命名空间
xmlns:aop=https://www.springframework.org/schema/aop
还需要配xsi:schemaLocation,为aop加一个网络地址。
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.3.xsd
我们需要一个aspectjweaver-jar包:
xml配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<!--?xml version="1.0" encoding="UTF-8"?-->
< beans xmlns = "https://www.springframework.org/schema/beans" xmlns:aop = "https://www.springframework.org/schema/aop" xmlns:context = "https://www.springframework.org/schema/context" xmlns:tx = "https://www.springframework.org/schema/tx" xmlns:xsi = "https://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.3.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.3.xsd
https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.3.xsd
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.3.xsd ">
<!-- 利用sop标签实现自动代理 -->
</ aop:aspectj-autoproxy >
<!-- 代理前原对象 -->
< bean class = "cn.hncu.xmlImpl.Person" id = "person" ></ bean >
<!-- 切面 = 切点+通知 -->
< bean class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" id = "advisor" >
<!-- 切点 -->
< property name = "patterns" >
< list >
< value >.*run.*</ value >
</ list >
</ property >
<!-- 通知-由我们写,实际代理动作 -->
< property name = "advice" >
< bean class = "cn.hncu.xmlImpl.AroundAdvice" id = "advice" ></ bean >
</ property >
</ bean >
</ beans >
|
测试方法:
1
2
3
4
5
6
7
|
@Test //自动代理
public void demo6(){
ApplicationContext ctx = new ClassPathXmlApplicationContext( "cn/hncu/xmlImpl/6.xml" );
Person p =ctx.getBean(Person. class );
p.run();
p.say();
}
|
测试结果:
个人觉得能学会使用一种就OK了,不用全部记下来,为了学习,都了解一下就好,别人写出来,能看懂就好。
哈哈,其实底层学好了,自己写的时候,就算不会用Spring的自动代理,自己写出来底层也是蛮好的嘛
总结
以上本文关于Spring AOP拦截-三种方式实现自动代理详解的全部内容,希望对大家有所帮助。有什么问题可以随时留言,小编会及时回复大家的。感谢朋友们对本站的支持!
原文链接:https://www.2cto.com/kf/201609/545023.html