手机用户请
横屏
获取最佳阅读体验,REFERENCES
中是本文参考的链接,如需要链接和更多资源,可以关注其他博客发布地址。
平台 | 地址 |
---|---|
CSDN | https://blog.csdn.net/sinat_28690417 |
简书 | https://www.jianshu.com/u/3032cc862300 |
个人博客 | https://yiyuery.github.io/NoteBooks/ |
Spring AOP 增强 Advice
Spring 使用增强类定义横切逻辑,同时由于Spring方法只支持方法连接点,增强还包括在方法的哪一点加入横切代码的方位信息。所以增强包括:1、横切逻辑;2、部分连接点的信息。
抽象接口 org.springframework.aop
按照增强在目标类方法中的连接点位置,可以分为以下5类:
前四种比较好理解,大致对应于被增强方法的执行时间,前、后、前后、异常抛出四个连接点。最后一种引介增强:IntroductionInterceptor
表示在目标类中添加一些新的方法和属性。
BeforeAdvice
package org.springframework.aop;
import org.aopalliance.aop.Advice;
/**
* Common marker interface for before advice, such as {@link MethodBeforeAdvice}.
*
* <p>Spring supports only method before advice. Although this is unlikely to change,
* this API is designed to allow field advice in future if desired.
*
* @author Rod Johnson
* @see AfterAdvice
*/
public interface BeforeAdvice extends Advice {
}
目标:记录方法执行开始时间
在上一篇《[Spring] Spring AOP 实现原理剖析(一)》的基础上继续开展实战
实现一个前置增强类用于业务类方法执行前的增强。
//方法增强接口(Spring中定义)
public interface MethodBeforeAdvice extends BeforeAdvice {
/**
* Callback before a given method is invoked.
* @param method method being invoked
* @param args arguments to the method
* @param target target of the method invocation. May be {@code null}.
* @throws Throwable if this object wishes to abort the call.
* Any exception thrown will be returned to the caller if it's
* allowed by the method signature. Otherwise the exception
* will be wrapped as a runtime exception.
*/
void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}
//增强类
public class BusinessLogHandlerBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
BusinessLogMonitor.begin(method.getName());
}
}
测试输出
/**
* 前置增强
*/
@Test
public void deletePersonWithBeforeAdvice() {
//创建被增强实例
PersonManagerServiceImpl personManagerService = new PersonManagerServiceImpl();
//创建前置增强Advice
BeforeAdvice beforeAdvice = new BusinessLogHandlerBeforeAdvice();
//Spring 提供的代理工厂
ProxyFactory factory = new ProxyFactory();
//设置代理目标
factory.setTarget(personManagerService);
//为代理目标添加增强
factory.addAdvice(beforeAdvice);
//生成代理实例
PersonManagerServiceImpl proxy = (PersonManagerServiceImpl)factory.getProxy();
//执行方法
proxy.deletePerson();
}
//23:44:01.043 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
//23:44:01.065 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
可以看到在 deletePerson
方法执行前,增强逻辑生效了,输出了
om.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
代理工厂 ProxyFactory
在上一篇《[Spring] Spring AOP 实现原理剖析(一)》曾提到过Spring AOP的底层实现用的还是JDK和CGLib的动态代理技术。
但是我们在使用CGLib时定义了代理类生成的一个辅助构造类
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
/**
* 创建代理类
* @param clazz
* @return
*/
public Object createProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
BusinessLogMonitor.begin(obj.getClass().getName()+"."+method.getName());
Object result = proxy.invokeSuper(obj, args);
BusinessLogMonitor.end();
return result;
}
}
在Spring
中,也定义了一个AopProxy
,并提供了2个实现类:
public interface AopProxy {
/**
* Create a new proxy object.
* <p>Uses the AopProxy's default class loader (if necessary for proxy creation):
* usually, the thread context class loader.
* @return the new proxy object (never {@code null})
* @see Thread#getContextClassLoader()
*/
Object getProxy();
/**
* Create a new proxy object.
* <p>Uses the given class loader (if necessary for proxy creation).
* {@code null} will simply be passed down and thus lead to the low-level
* proxy facility's default, which is usually different from the default chosen
* by the AopProxy implementation's {@link #getProxy()} method.
* @param classLoader the class loader to create the proxy with
* (or {@code null} for the low-level proxy facility's default)
* @return the new proxy object (never {@code null})
*/
Object getProxy(@Nullable ClassLoader classLoader);
}
从名字可以看出,分别对应两种AOP实现机制,如果是针对接口进行代理,则使用JdkDynamicAopProxy
;如果是针对实例类的代理,则使用CglibAopProxy
相应的,若指定JDK代理技术,需要传入interfaces
参数。另外,ProxyFactory
可以通过factory.setOptimize(true);
启动优化代理方式,这样,针对接口的代理也会使用CglibAopProxy
。
Spring 中 xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1、被增强类-->
<bean id="target" class="com.example.spring.aop.service.impl.PersonManagerServiceImpl"/>
<!--2、增强类-->
<bean id="businessLogHandlerBeforeAdvice" class="com.example.spring.aop.advice.BusinessLogHandlerBeforeAdvice"/>
<!--3、代理工厂定义-->
<!--3.1 指定代理的接口-->
<!--3.2 指定使用的增强-->
<!--3.3 指定对哪个bean进行代理-->
<bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.example.spring.aop.service.IPersonManagerService"
p:interceptorNames="businessLogHandlerBeforeAdvice"
p:target-ref="target"
/>
</beans>
测试输出
/**
* Spring XML 配置前置增强
*/
@Test
public void deletePersonWithBeforeAdviceBySpringXML() {
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/aop-before-advice.xml");
IPersonManagerService bean = (IPersonManagerService)context.getBean("personManagerImpl");
bean.deletePerson();
log.info("-----------------------");
bean.modifyPerson(new PersonDO("xx1"));
}
//00:27:02.946 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
//00:27:02.946 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
//00:27:05.951 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImplTest - -----------------------
//00:27:05.951 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
//00:27:05.952 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据修改:xx1
分析:
MethodBeforeAdvice
其实看了前置增强,后置、坏绕对应的实现也大相径庭,此处就不再追溯,贴了代码,直接看吧。
后置实现:
public interface AfterAdvice extends Advice {
}
public interface AfterReturningAdvice extends AfterAdvice {
/**
* Callback after a given method successfully returned.
* @param returnValue the value returned by the method, if any
* @param method method being invoked
* @param args arguments to the method
* @param target target of the method invocation. May be {@code null}.
* @throws Throwable if this object wishes to abort the call.
* Any exception thrown will be returned to the caller if it's
* allowed by the method signature. Otherwise the exception
* will be wrapped as a runtime exception.
*/
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
public class BusinessLogHandlerAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
BusinessLogMonitor.end();
}
}
/**
* Spring XML 配置后置增强
*/
@Test
public void deletePersonWithAfterAdviceBySpringXML() {
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/aop-after-advice.xml");
IPersonManagerService bean = (IPersonManagerService)context.getBean("personManagerImpl");
bean.deletePerson();
log.info("-----------------------");
bean.modifyPerson(new PersonDO("xx1"));
}
//00:38:24.737 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
//00:38:27.739 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - end monitor....
//00:38:27.740 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImplTest - -----------------------
//00:38:27.740 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据修改:xx1
//00:38:30.745 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - end monitor....
分析:
AfterAdvice
此处顺便提下如何配置多个增强:
比如同时配置前置和后置增强:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1、被增强类-->
<bean id="target" class="com.example.spring.aop.service.impl.PersonManagerServiceImpl"/>
<!--2、增强类-->
<bean id="businessLogHandlerBeforeAdvice" class="com.example.spring.aop.advice.BusinessLogHandlerBeforeAdvice"/>
<bean id="businessLogHandlerAfterAdvice" class="com.example.spring.aop.advice.BusinessLogHandlerAfterAdvice"/>
<!--3、代理工厂定义-->
<!--3.1 指定代理的接口-->
<!--3.2 指定使用的增强-->
<!--3.3 指定对哪个bean进行代理-->
<bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.example.spring.aop.service.IPersonManagerService"
p:interceptorNames="businessLogHandlerBeforeAdvice,businessLogHandlerAfterAdvice"
p:target-ref="target"
/>
</beans>
测试输出
/**
* Spring XML 配置前、后置增强
*/
@Test
public void deletePersonWithBeforeAndAfterAdviceBySpringXML() {
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/aop-before-and-after-advice.xml");
IPersonManagerService bean = (IPersonManagerService)context.getBean("personManagerImpl");
bean.deletePerson();
log.info("-----------------------");
bean.modifyPerson(new PersonDO("xx1"));
}
//23:28:11.627 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
//23:28:11.628 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
//23:28:14.629 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - end monitor....
//23:28:14.630 [main] INFO com.example.spring.aop.simple.BusinessLogHandler - deletePerson执行耗时3001毫秒
//23:28:14.630 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImplTest - -----------------------
//23:28:14.630 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
//23:28:14.630 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据修改:xx1
//23:28:17.633 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - end monitor....
//23:28:17.633 [main] INFO com.example.spring.aop.simple.BusinessLogHandler - modifyPerson执行耗时3003毫秒
分析:
p:interceptorNames="businessLogHandlerBeforeAdvice,businessLogHandlerAfterAdvice"
实现。interceptorNames
是数组形式的参数,接受增强Bean的名称。也可以采用如下方式配置:
<bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.example.spring.aop.service.IPersonManagerService"/>
<property name="interceptorNames">
<list>
<idref bean="businessLogHandlerAfterAdvice"/>
<idref bean="businessLogHandlerBeforeAdvice"/>
</list>
</property>
<property name="target" ref="target"/>
</bean>
便于 IDEA 可以自动检查出错误并提示。
综合实现前置、后置增强。具体如下:
// 调整编辑方法,使其修改传入数据后并返回,模拟有数据返回的情况
@Override
public PersonDO modifyPerson(PersonDO personDO) {
log.info("模拟人员数据修改:"+personDO.getName());
try {
Thread.sleep(3000);
} catch (Exception e) {
log.error("PersonManagerServiceImpl modifyPerson failed!");
}
personDO.setName("被修改_"+personDO.getName());
return personDO;
}
//增强类实现
public class BusinessLogHandlerAroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
BusinessLogMonitor.begin(invocation.getMethod().getName());
Object object = invocation.proceed();
BusinessLogMonitor.end();
return object;
}
}
Spring配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1、被增强类-->
<bean id="target" class="com.example.spring.aop.service.impl.PersonManagerServiceImpl"/>
<!--2、增强类-->
<bean id="businessLogHandlerAroundAdvice" class="com.example.spring.aop.advice.BusinessLogHandlerAroundAdvice"/>
<!--3、代理工厂定义-->
<!--3.1 指定代理的接口-->
<!--3.2 指定使用的增强-->
<!--3.3 指定对哪个bean进行代理-->
<!-- <bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.example.spring.aop.service.IPersonManagerService"
p:interceptorNames="businessLogHandlerAroundAdvice"
p:target-ref="target"/>-->
<bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.example.spring.aop.service.IPersonManagerService"/>
<property name="interceptorNames">
<list>
<idref bean="businessLogHandlerAroundAdvice"/>
</list>
</property>
<property name="target" ref="target"/>
</bean>
</beans>
编写测试类并输出测试结果:
/**
* 环绕增强
*/
@Test
public void deletePersonWithAroundAdviceBySpringXML() {
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/aop-around-advice.xml");
IPersonManagerService bean = (IPersonManagerService)context.getBean("personManagerImpl");
bean.deletePerson();
log.info("-----------------------");
PersonDO xx1 = bean.modifyPerson(new PersonDO("xx1"));
log.info("修改返回结果>>>>"+xx1.getName());
}
//00:18:11.646 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
//00:18:11.646 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
//00:18:14.650 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - end monitor....
//00:18:14.651 [main] INFO com.example.spring.aop.simple.BusinessLogHandler - deletePerson执行耗时3005毫秒
//00:18:14.651 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImplTest - -----------------------
//00:18:14.651 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
//00:18:14.651 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据修改:xx1
//00:18:17.656 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - end monitor....
//00:18:17.656 [main] INFO com.example.spring.aop.simple.BusinessLogHandler - modifyPerson执行耗时3005毫秒
//00:18:17.656 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImplTest - 修改返回结果>>>>被修改_xx1
分析
org.aopalliance.intercept.MethodInterceptor
invocation.proceed()
方法执行前后加入增强逻辑来实现环绕增强异常增强和前几个增强接口定义不太一样,仅仅定义了个标签接口
ThrowsAdvice
,实际运行时 Spring 根据反射机制自行判断符合条件的方法签名,进行增强。
首先,补充个会抛出异常的方法定义:
@Override
public void deleteThrowException() {
log.info("模拟人员数据删除,抛出异常");
try {
Thread.sleep(3000);
} catch (Exception e) {
log.error("PersonManagerServiceImpl deletePerson failed!");
}
throw new IllegalArgumentException("删除失败,抛出异常");
}
然后,根据约定的签名规则定义增强方法来处理异常:
@Slf4j
public class BusinessLogHandlerThrowExceptionAdvice implements ThrowsAdvice {
/**
* ThrowsAdvice 是个标签接口,运行期 Spring 使用反射机制自行判断,必须采用签名形式定义异常抛出的增强方法
* void afterThrowing(Method method,Object args,Object target,Throwable ex)
* @param method
* @param args
* @param target
* @param ex
* @throws Throwable
*/
public void afterThrowing(Method method,Object args,Object target,Exception ex) throws Throwable{
log.error("BusinessLogHandlerThrowExceptionAdvice >>> method: "+ method.getName());
}
}
Spring 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1、被增强类-->
<bean id="target" class="com.example.spring.aop.service.impl.PersonManagerServiceImpl"/>
<!--2、增强类-->
<bean id="businessLogHandlerThrowExceptionAdvice" class="com.example.spring.aop.advice.BusinessLogHandlerThrowExceptionAdvice"/>
<!--3、代理工厂定义-->
<!--3.1 指定代理的接口-->
<!--3.2 指定使用的增强-->
<!--3.3 指定对哪个bean进行代理-->
<!-- <bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.example.spring.aop.service.IPersonManagerService"
p:interceptorNames="businessLogHandlerThrowExceptionAdvice"
p:target-ref="target"/>-->
<bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.example.spring.aop.service.IPersonManagerService"/>
<property name="interceptorNames">
<list>
<idref bean="businessLogHandlerThrowExceptionAdvice"/>
</list>
</property>
<property name="target" ref="target"/>
</bean>
</beans>
测试输出
/**
* 异常增强
*/
@Test
public void deletePersonWithThrowAdviceBySpringXML() {
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/aop-throw-exception-advice.xml");
IPersonManagerService bean = (IPersonManagerService)context.getBean("personManagerImpl");
bean.deletePerson();
log.info("-----------------------");
try {
bean.deleteThrowException();
}catch (Exception e){
log.error("deletePersonWithThrowAdviceBySpringXML catch exception!",e);
}
}
//23:44:52.021 [main] DEBUG org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor - Found exception handler method on throws advice: public void com.example.spring.aop.advice.BusinessLogHandlerThrowExceptionAdvice.afterThrowing(java.lang.reflect.Method,java.lang.Object,java.lang.Object,java.lang.Exception) throws java.lang.Throwable
//23:44:52.023 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
//23:44:55.027 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImplTest - -----------------------
//23:44:55.027 [main] DEBUG org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor - Found exception handler method on throws advice: public void com.example.spring.aop.advice.BusinessLogHandlerThrowExceptionAdvice.afterThrowing(java.lang.reflect.Method,java.lang.Object,java.lang.Object,java.lang.Exception) throws java.lang.Throwable
//23:44:55.028 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除,抛出异常
//23:44:58.031 [main] ERROR com.example.spring.aop.advice.BusinessLogHandlerThrowExceptionAdvice - BusinessLogHandlerThrowExceptionAdvice >>> method: deleteThrowException
//23:44:58.036 [main] ERROR com.example.spring.aop.service.impl.PersonManagerServiceImplTest - deletePersonWithThrowAdviceBySpringXML catch exception!
//java.lang.IllegalArgumentException: 删除失败,抛出异常
// at com.example.spring.aop.service.impl.PersonManagerServiceImpl.deleteThrowException(PersonManagerServiceImpl.java:74)
// at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
// at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
// at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
// at java.lang.reflect.Method.invoke(Method.java:498)
分析
规则:
afterThrowing
方法。一种特殊形式增强,它不是在目标方法周围织入增强,而是为目标类创建新的方法和属性,所以引介增强的连接点是类级别的,而非方法级别。
特点
前文,我们对所有方法织入了业务日志的增强,由于业务日志的输出往往会增加系统的负担,我们可以通过引介增强来实现这个业务日志输出的功能开关。
首先,定义一个被增强类需要增强的能力接口,目的是通过其子类实现该接口能力
public interface BusinessLogHandlerIntroduceSwitch {
/*定义开关*/
void setSwitch(boolean open);
}
然后,定义增强逻辑,可以加上接口中定义的方法,实现模板方法类似的效果:
/*根据手动设置的开关,判断业务日志增强是否开启*/
public class BusinessLogHandlerIntroduceAdvice extends DelegatingIntroductionInterceptor implements BusinessLogHandlerIntroduceSwitch {
private ThreadLocal<Boolean> switchMap = new ThreadLocal<>();
@Override
public void setSwitch(boolean open) {
switchMap.set(open);
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object obj = null;
if (Objects.nonNull(switchMap.get()) && switchMap.get()) {
BusinessLogMonitor.begin(mi.getMethod().getName());
obj = super.invoke(mi);
BusinessLogMonitor.end();
}else{
obj = super.invoke(mi);
}
return obj;
}
}
Spring 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1、被增强类-->
<bean id="personManagerImplTarget" class="com.example.spring.aop.service.impl.PersonManagerServiceImpl"/>
<!--2、增强类-->
<bean id="businessLogHandlerIntroduceAdvice" class="com.example.spring.aop.advice.introduce.BusinessLogHandlerIntroduceAdvice"/>
<!--3、代理工厂定义-->
<!--3.1 指定代理的接口-->
<!--3.2 指定使用的增强-->
<!--3.3 指定对哪个bean进行代理-->
<!-- <bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interfaces="com.example.spring.aop.advice.introduce.BusinessLogHandlerIntroduceSwitch"
p:interceptorNames="businessLogHandlerIntroduceAdvice"
p:proxyTargetClass="true"
p:target-ref="personManagerImplTarget"/>-->
<bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.example.spring.aop.advice.introduce.BusinessLogHandlerIntroduceSwitch"/>
<property name="interceptorNames">
<list>
<idref bean="businessLogHandlerIntroduceAdvice"/>
</list>
</property>
<property name="target" ref="personManagerImplTarget"/>
<!--由于引介增强一定要通过创建子类来生成代理,所以需要强制使用CGLib-->
<property name="proxyTargetClass" value="true"/>
</bean>
</beans>
测试
/**
* 引介增强
*/
@Test
public void deletePersonWithIntroduceAdviceBySpringXML() {
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/aop-introduce-advice.xml");
PersonManagerServiceImpl bean = (PersonManagerServiceImpl)context.getBean("personManagerImpl");
bean.deletePerson();
log.info("--------------------------");
//开启增强
BusinessLogHandlerIntroduceSwitch enhancer = (BusinessLogHandlerIntroduceSwitch)bean;
enhancer.setSwitch(true);
bean.deletePerson();
}
//00:25:12.774 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
//00:25:15.778 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImplTest - --------------------------
//00:25:15.780 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
//00:25:15.782 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
//00:25:18.783 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - end monitor....
//00:25:18.784 [main] INFO com.example.spring.aop.simple.BusinessLogHandler - deletePerson执行耗时3002毫秒
分析
interfaces
,而不再是通过JDK通道代理,生成被增强类的代理类DelegatingIntroductionInterceptor
,并通过覆盖父类的invoke方法,结合增强接口,实现自身增强逻辑。本文,通过实战代码,详细介绍了Spring中五种增强方式各自的实现方式。其中,前、后、坏绕、异常增强使用的是JDK动态代理,引介增强强制使用CGLib的方式实现。
下一篇,我们将就切点、切面的控制做进一步的了解。
To be continue....