1. 程式人生 > >Spring AOP的用法

Spring AOP的用法

val around 技術 pac factor 日常 三種方式 viso 可復用

AOP在事務處理、日誌、安全等方面用的很多,在日常軟件定制開發中,用好AOP可以進一步解耦,增強代碼的可復用性。平時用的最多的還是Spring AOP動態代理,其用法如下:

第一種實現的方式:通過Spring的API實現AOP。

第一步:
  1. public interface UserService {
  2. public void add();
  3. public void update(int a);
  4. public void delete();
  5. public void search();
  6. }
第二步:
  1. public class UserServiceImpl implements UserService {
  2. @Override
  3. public void add() {
  4. System.out.println("增加用戶");
  5. }
  6. @Override
  7. public void update(int a) {
  8. System.out.println("修改用戶");
  9. }
  10. @Override
  11. public void delete() {
  12. System.out.println("刪除用戶");
  13. }
  14. @Override
  15. public void search() {
  16. System.out.println("查詢用戶");
  17. }
第三步:實現MethodBeforeAdvice的接口,Spring框架當中為我們提供了很多中通知。
  1. public class Log implements MethodBeforeAdvice{
  2. /**
  3. * @param method 被調用方法對象
  4. * @param args 被調用的方法的參數
  5. * @param target 被調用的方法的目標對象
  6. * */
  7. @Override
  8. public void before(Method method, Object[] args, Object target)
  9. throws Throwable {
  10. System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被執行");
  11. }
  12. }
第四步:配置beans.xml文件
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/aop
  8. http://www.springframework.org/schema/aop/spring-aop.xsd">
  9. <bean id="userService" class="com.spring.service.impl.UserServiceImpl"/>
  10. <!-- 這個切面也要配置成bean-->
  11. <bean id="log" class="com.spring.advice.Log"/>
  12. <aop:config>
  13. <!--切入點,需要告訴方法在什麽去執行
  14. expression="execution(* com.spring.service.impl.*.*(..))"
  15. 第一個* 表示所有的返回值,然後就是包名
  16. 第二個*表示所有的類對象
  17. 第三個*表示類對象所有的方法
  18. 第四個*表示所有方法下面的帶參數的方法或者是不帶參數的方法
  19. -->
  20. <aop:pointcut expression="execution(* com.spring.service.impl.*.*(..))" id="pointcut"/>
  21. <!-- 在所有的方法中都切入前置通知-->
  22. <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
  23. </aop:config>
  24. </beans>
第五步:測試:
  1. package com.spring.test;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. import com.spring.service.UserService;
  5. public class Test {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
  8. UserService userService = (UserService)ac.getBean("userService");
  9. userService.update(2);
  10. userService.add();
  11. }
  12. }
運行結果:
  1. 三月 12, 2017 2:22:44 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
  2. 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@439f5b3d: startup date [Sun Mar 12 14:22:44 GMT+08:00 2017]; root of context hierarchy
  3. 三月 12, 2017 2:22:44 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
  4. 信息: Loading XML bean definitions from class path resource [beans.xml]
  5. com.spring.service.impl.UserServiceImplupdate方法被執行
  6. 修改用戶
  7. com.spring.service.impl.UserServiceImpladd方法被執行
  8. 增加用戶
故前置通知可以在spring當中被執行,接下可以完善通知;
  1. public class AfterLog implements AfterReturningAdvice{
  2. /**
  3. * 目標方法執行後執行的通知
  4. * returnValue--返回值
  5. * method 被調用的方法對象
  6. * args 被調用的方法對象的參數
  7. * target 被調用的方法對象的目標對象
  8. * */
  9. @Override
  10. public void afterReturning(Object returnValue, Method method,
  11. Object[] args, Object target) throws Throwable {
  12. System.out.println(target.getClass().getName()+"的"+method.getName()+"被成功執行,返回值是:"+returnValue);
  13. }
  14. }
  1. import java.lang.reflect.Method;
  2. import org.springframework.aop.ThrowsAdvice;
  3. public class ExceptionLog implements ThrowsAdvice {
  4. public void afterThrowing(Method method,Exception ex) throws Throwable {
  5. }
  6. }
重新配置:
  1. <!-- 這個切面也要配置成bean-->
  2. <bean id="log" class="com.spring.advice.Log"/>
  3. <bean id="afterLog" class="com.spring.advice.AfterLog"></bean>
  4. <aop:config>
  5. <!--切入點,需要告訴方法在什麽去執行
  6. expression="execution(* com.spring.service.impl.*.*(..))"
  7. 第一個* 表示所有的返回值,然後就是包名
  8. 第二個*表示所有的類對象
  9. 第三個*表示類對象所有的方法
  10. 第四個*表示所有方法下面的帶參數的方法或者是不帶參數的方法
  11. -->
  12. <aop:pointcut expression="execution(* com.spring.service.impl.*.*(..))" id="pointcut"/>
  13. <!-- 在所有的方法中都切入前置通知-->
  14. <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
  15. <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
  16. </aop:config>
測試運行結果:
  1. 三月 12, 2017 2:28:19 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
  2. 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@439f5b3d: startup date [Sun Mar 12 14:28:19 GMT+08:00 2017]; root of context hierarchy
  3. 三月 12, 2017 2:28:19 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
  4. 信息: Loading XML bean definitions from class path resource [beans.xml]
  5. com.spring.service.impl.UserServiceImpl的update方法被執行
  6. 修改用戶
  7. com.spring.service.impl.UserServiceImpl的update被成功執行,返回值是:null
  8. com.spring.service.impl.UserServiceImpl的add方法被執行
  9. 增加用戶
  10. com.spring.service.impl.UserServiceImpl的add被成功執行,返回值是:null
總結:AOP的重要性,非常重要 Spring的AOP就是將公共的業務(如日誌,安全等)和業務類結合。當執行業務的時候將會把公共業務加進來。實現公共業務的重復利用。我們自己的業務就會變得更加的純粹,我們就可以關註我們的自己的業務,本質就是動態代理。 第二種方式:自定義類來實現AOP,不實現spring的自帶的通知 第一步:重新通知:
  1. public class Log {
  2. public void before(){
  3. System.out.println("方法執行前");
  4. }
  5. public void after(){
  6. System.out.println("方法執行後");
  7. }
  8. }
第二步:重新寫配置文件
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/aop
  8. http://www.springframework.org/schema/aop/spring-aop.xsd">
  9. <bean id="userService" class="com.spring.service.impl.UserServiceImpl"/>
  10. <!-- 這個切面也要配置成bean-->
  11. <bean id="log" class="com.spring.advice.Log"/>
  12. <aop:config>
  13. <!--切入點,需要告訴方法在什麽去執行
  14. expression="execution(* com.spring.service.impl.*.*(..))"
  15. 第一個* 表示所有的返回值,然後就是包名
  16. 第二個*表示所有的類對象
  17. 第三個*表示類對象所有的方法
  18. 第四個*表示所有方法下面的帶參數的方法或者是不帶參數的方法
  19. -->
  20. <aop:aspect ref="log">
  21. <aop:pointcut expression="execution(* com.spring.service.impl.*.*(..))" id="pointcut"/>
  22. <aop:before method="before" pointcut-ref="pointcut"/>
  23. <aop:after method="after" pointcut-ref="pointcut"/>
  24. </aop:aspect>
  25. </aop:config>
  26. </beans>
第三種方式:通過註解實現AOP 第一步:修改log
  1. package com.spring.advice;
  2. import java.lang.reflect.Method;
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.After;
  5. import org.aspectj.lang.annotation.Around;
  6. import org.aspectj.lang.annotation.Aspect;
  7. import org.aspectj.lang.annotation.Before;
  8. import org.springframework.aop.MethodBeforeAdvice;
  9. @Aspect
  10. public class Log {
  11. @Before("execution(* com.spring.service.impl.*.*(..))")
  12. public void before(){
  13. System.out.println("方法執行前");
  14. }
  15. @After("execution(* com.spring.service.impl.*.*(..))")
  16. public void after(){
  17. System.out.println("方法執行後");
  18. }
  19. @Around("execution(* com.spring.service.impl.*.*(..))")
  20. public Object around(ProceedingJoinPoint jp) throws Throwable{
  21. System.out.println("環繞前");
  22. System.out.println("方法"+jp.getSignature());
  23. Object result=jp.proceed();
  24. System.out.println("環繞後");
  25. return result;
  26. }
  27. }
第二步:修改beans.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/aop
  8. http://www.springframework.org/schema/aop/spring-aop.xsd">
  9. <bean id="userService" class="com.spring.service.impl.UserServiceImpl"/>
  10. <!-- 這個切面也要配置成bean-->
  11. <bean id="log" class="com.spring.advice.Log"/>
  12. <aop:aspectj-autoproxy/>
  13. </beans>
第三步:運行:
  1. 三月 12, 2017 3:00:02 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
  2. 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@439f5b3d: startup date [Sun Mar 12 15:00:02 GMT+08:00 2017]; root of context hierarchy
  3. 三月 12, 2017 3:00:02 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
  4. 信息: Loading XML bean definitions from class path resource [beans.xml]
  5. 環繞前
  6. 方法void com.spring.service.UserService.update(int)
  7. 方法執行前
  8. 修改用戶
  9. 環繞後
  10. 方法執行後

Spring總結(五)--Spring中使用AOP三種方式

裏面最關鍵的切面配置如下:

技術分享

Spring AOP的用法