9-15 3,095 views
AOP
AOP(Aspect Oriented Programing,面向切面编程)用于在不侵入原有代码的基础上,为代码统一添加新功能,例如性能监控、日志记录、事务管理等。AOP的原理如图所示:
其中:
1)连接点(Jointpoint),表示方法执行的某个位置,如方法调用前、方法调用后、方法抛出异常等;
2)通知(Advice),表示需要在某个连接点加入的新功能,通知包括以下5种类型:Before advice,After returning advice,After throwing advice,After (finally) advice,Around advice;
3)切入点(Pointcut),用于描述某些类的某些方法;
4)切面(Aspect),通知和切入点组成切面,通过切面实现在指定类的指定方法上,加入通知。
Spring AOP的4种实现
Spring AOP的实现基于动态代理,有以下4种实现方式:
1)基于Aspect注解;
2)基于aop标签配置;
3)基于ProxyFactoryBean;
4)基于DefaultAdvisorAutoProxyCreator。
通过一个例子分别说明上述4种实现方式。例子中包含TestService接口及其实现TestServiceImpl,TestServiceImpl的test方法输出“execute test method”:
1 2 3 4 5 6 7 |
package com.magicwt.service; public interface TestService { public void test(); } |
1 2 3 4 5 6 7 8 9 10 11 |
package com.magicwt.service.impl; import com.magicwt.service.TestService; public class TestServiceImpl implements TestService { public void test() { System.out.println("execute test method"); } } |
main方法初始化Spring上下文,获取TestService实例,并执行test方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.magicwt; import com.magicwt.service.TestService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("context.xml"); TestService testService = (TestService) applicationContext.getBean("testService"); testService.test(); } } |
Spring上下文配置文件context.xml:
1 2 3 4 5 6 7 8 9 10 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <bean id="testService" class="com.magicwt.service.impl.TestServiceImpl"/> </beans> |
执行main方法,输出:
execute test method
以下通过Spring AOP,在test方法调用前和调用后,增加切面。
基于Aspect注解
新建类TestAspect:
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 com.magicwt.aop; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; /** * 配置切面和组件 */ @Component @Aspect public class TestAspect { /** * 配置切入点,com.magicwt.service包下所有类的所有方法 */ @Pointcut("execution(* com.magicwt.service..*(..))") public void pointcut() {} /** * 方法调用前通知 */ @Before("pointcut()") public void before() { System.out.println("execute before advice"); } /** * 方法调用后通知 */ @After("pointcut()") public void after() { System.out.println("execute after advice"); } } |
context.xml修改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"> <bean id="testService" class="com.magicwt.service.impl.TestServiceImpl"/> <!-- 扫描com.magicwt.aop包下的组件,进行初始化 --> <context:component-scan base-package="com.magicwt.aop"/> <!-- 根据注解自动创建代理,织入切面 --> <aop:aspectj-autoproxy /> </beans> |
执行main方法,输出:
execute before advice
execute test method
execute after advice
基于aop标签配置
TestAspect:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.magicwt.aop; public class TestAspect { public void before() { System.out.println("execute before advice"); } public void after() { System.out.println("execute after advice"); } } |
context.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 27 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"> <bean id="testService" class="com.magicwt.service.impl.TestServiceImpl"/> <bean id="testAspect" class="com.magicwt.aop.TestAspect"/> <aop:config> <!-- 配置切面 --> <aop:aspect ref="testAspect"> <!-- 配置切入点,com.magicwt.service包下所有类的所有方法 --> <aop:pointcut id="pointcut" expression="execution(* com.magicwt.service..*(..))"/> <!-- 配置方法调用前通知 --> <aop:before method="before" pointcut-ref="pointcut"/> <!-- 配置方法调用后通知 --> <aop:after method="after" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> </beans> |
执行main方法,输出:
execute before advice
execute test method
execute after advice
基于ProxyFactoryBean
新建类TestAdvice,实现接口MethodBeforeAdvice、AfterReturningAdvice,重写before、afterReturning方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package com.magicwt.aop; import org.springframework.aop.AfterReturningAdvice; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class TestAdvice implements MethodBeforeAdvice, AfterReturningAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("execute before advice"); } @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("execute after advice"); } } |
context.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 27 28 29 30 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <bean id="realTestService" class="com.magicwt.service.impl.TestServiceImpl"/> <bean id="testAdvice" class="com.magicwt.aop.TestAdvice"/> <!-- 配置切入点,com.magicwt.service包下所有类的所有方法 --> <bean id="pointcut" class="org.springframework.aop.aspectj.AspectJExpressionPointcut"> <property name="expression" value="execution(* com.magicwt.service..*(..))"/> </bean> <!-- 配置切面 --> <bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice" ref="testAdvice"/> <property name="pointcut" ref="pointcut"/> </bean> <!-- 创建代理,织入切面 --> <bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="realTestService"/> <property name="interceptorNames" value="advisor" /> <property name="proxyInterfaces" value="com.magicwt.service.TestService" /> </bean> </beans> |
执行main方法,输出:
execute before advice
execute test method
execute after advice
基于DefaultAdvisorAutoProxyCreator
与基于ProxyFactoryBean的实现相比,只需修改context.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="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <bean id="testService" class="com.magicwt.service.impl.TestServiceImpl"/> <bean id="testAdvice" class="com.magicwt.aop.TestAdvice"/> <!-- 配置切入点,com.magicwt.service包下所有类的所有方法 --> <bean id="pointcut" class="org.springframework.aop.aspectj.AspectJExpressionPointcut"> <property name="expression" value="execution(* com.magicwt.service..*(..))"/> </bean> <!-- 配置切面 --> <bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice" ref="testAdvice"/> <property name="pointcut" ref="pointcut"/> </bean> <!-- 通过DefaultAdvisorAutoProxyCreator自动创建代理,织入切面 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> </beans> |
执行main方法,输出:
execute before advice
execute test method
execute after advice
版权属于: 我爱我家
转载时必须以链接形式注明原始出处及本声明。