Spring AOP的用法

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的用法