AOP:
术语:
连接点:可以被切面织入的方法(这里的 可以 指的是在容器中注册为连接点)
切入点:具体要被织入的方法
目标对象:要被织入的方法所在的对象
通知(Advice):切面的一种实现,可以完成简单的织入功能。定义了织入时间。即增强的业务什么时候实现,主业务之前或者之后
顾问(Advisor):将通知进一步包装。可以选择增强的方法
用代理实现AOP:将交叉业务和系统级服务放在代理中。
AOP环境搭建:
2)原来的applicationContext.xml规范
通知(Advice):AOP
1)MethodBeforeAdvice : 前置通知
定义实现该接口的类(切面)
注册该类
<!-- 切面 -->
<bean id="before" class="MyMethodBeforeAdvice"/>
注册代理工厂bean,用来提供代理对象,
<bean id="Factory" class="org.springframework.aop.framework.ProxyFactoryBean">
设置工厂的参数:
<property name="targetName" value="someService"/>
或者
<property name="target" ref = "service.ISomeServiceImpl"/>
配置切面:
<!-- 切面 -->
<property name="interceptorNames" value="before"
2)AfterRunningAdvice:后置通知,多了业务方法返回值,其余同上
3)MethodInterceptor:环绕通知
public class myMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// TODO Auto-generated method stub
System.out.println("之前");
//注意:这个方法返回值是业务里doFirst方法返回值
Object result = invocation.proceed();
System.out.println("之后");
return result;
}
}
输出 :
之前
执行doFirst方法
之后
参数invocation.proceed方法执行业务方法
4)ThrowsAdvice:异常通知
//异常通知
public class myThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(Exception ex) {
System.out.println("执行异常通知方法" +ex.getMessage() );
}
}
给对象织入多个切面:
<property name="interceptorNames">
<array>
<value>before</value>
</array>
</property>
<!-- <property name="interceptorNames" value="用逗号分割"> -->
使用<bean id="Factory" class="org.springframework.aop.framework.ProxyFactoryBean">
这种方式:有接口会生成JDKDynamicProxy对象,没有接口会使用CGLIB动态代理
在有接口情况下使用CGLIB代理:
增加一个property-><property name="proxyTargetClass" value="true">
或者:<property name="optimize" value="true">
顾问:选择切入点(Advice所有方法都切入,只是简单实现)
PointcutAdvisor接口常用实现类:
NameMatchMethodPonitcutAdvisor:名称匹配方法切入点顾问
<!-- 切面 -->
<bean id="before" class="MyMethodBeforeAdvice"/>
<!-- 注册Advisor -->
<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="before"/>
<property name="mappedName" value="doFirst"/>
</bean>
使用mappedNames匹配多个方法
<property name="mappedName" value="*ir*"/> ---> 使用通配符匹配带有ir的
使用顾问(而不是切面)
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- <property name="targetName" value="someService"/> -->
<property name="target" ref ="someService"/>
<!-- 包装切面 -->
<property name="interceptorNames" value="myAdvisor" />
</bean>
RegexMethodPointcutAdvisor : 正则表达式匹配方法切入点顾问
正则表达式:
运算符 | 名称 | 意义 |
. | 点号 | 表示任意单个字符 |
+ | 加号 | 表示前一个字符出现一次或者多次 |
* | 星号 | 表示前一个字符出现0次或者多次 |
| | A | B 模式A或者模式B | 或者 |
<bean id="myAdvisor2" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="before"/>
<property name="pattern" value=".*i.*"/> //任意字符出现一次或者多次,使用patterns匹配多个模式
</bean>
注意:pattern匹配的是全限定性方法名,doFirst无法匹配dofirst方法,.*doFirst可以匹配
问题 : 如果被代理对象有多个,那么代理bean需要多个。
自动代理生成器(均继承自bean后处理器BeanPostProcessor,容器中所有Bean在初始化时均会自动执行Bean后处理器中的方法,故其无需id属性):
默认advisor自动代理生成器
bean名称自动代理生成器
1)默认advisor自动代理生成器:
<!-- 注册自动代理生成器 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
缺點:默認使用顧問(容器里配置的顾问),所有bean的顾问指定方法都会织入
2)bean名稱自動代理生成器:可以實現對指定bean的切入和指定方法的切入
<!-- bean名称自动代理生成器 -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >
<property name="beanNames" value="someService"/>
<!-- 还能指定切面 -->
<property name="interceptorNames" value="myAdvisor"/>
</bean>