Spring学习(六)-面向切面编程(AOP)
2017-08-24 20:35
721 查看
在软件系统中,存在一些功能需要用到应用程序的多个地方,但是我们又不想在每个点都去调用它,比如日志,事务管理,安全等。如果我们让应用对象只关注于自己所针对的业务领域问题,而上述这些功能由其他应用对象自行处理。为解决上述问题,Spring提出了面向切面的编程思想。在给出AOP的具体实现之前,先给出AOP相关的一些具体概念。
1、基本概念
(1)横切关注点
在软件开发过程中,散布于应用中多处的功能。面向切面编程的目的就是解决把横切关注点和业务逻辑相分离。
切面:把横切关注点模块化成为一些特殊的类。切面告诉我们是什么,在何时何处完成 其功能。
(2)通知
在AOP中,切面的工作称之为通知。通知主要定义了切面是什么,以及何时使用。
Spring切面可以应用5种类型的通知:
前置通知(Before):在目标方法被调用之前调用通知功能;
后置通知(After):在目标方法完成之后调用,此时不会关心方法的输出是什么;
返回通知(After-returning):在目标方法执行成功后调用通知;
异常通知(After-throwing):在目标方法抛出异常后调用通知;
环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
(3)切点
切点定义了通知在何处执行。切点和通知结合构成了一个完整的切面。
2、AOP具体实现
除了Spring的基础jar外,还需要额外导入aspectjweaver.jar,aopalliance.jar,aspectjrt.jar
(1)在XML中声明切面
定义一个接口IHelloWorldService :
编写接口的实现HelloWorldService :
定义切面HelloWorldAspect:
定义配置文件spring-aop.xml:
程序测试:
最终执行结果为:
(2)使用注解创建切面
我们利用XML方式实现了AOP的五种通知类型,然而在实际开发中,使用比较多的还是利用注解的方式实现注入,下面利用注解实现切面的五种通知类型。
接口IHelloWorldService和接口的实现类HelloWorldService同上一个实例。
修改切面HelloWorldAspect
定义spring-aop.xml
在xml中声明aspect的代理对象,使得在初始化spring 容器的时候,spring会自动对切点生成代理对象。如下:
运行结果为:
1、基本概念
(1)横切关注点
在软件开发过程中,散布于应用中多处的功能。面向切面编程的目的就是解决把横切关注点和业务逻辑相分离。
切面:把横切关注点模块化成为一些特殊的类。切面告诉我们是什么,在何时何处完成 其功能。
(2)通知
在AOP中,切面的工作称之为通知。通知主要定义了切面是什么,以及何时使用。
Spring切面可以应用5种类型的通知:
前置通知(Before):在目标方法被调用之前调用通知功能;
后置通知(After):在目标方法完成之后调用,此时不会关心方法的输出是什么;
返回通知(After-returning):在目标方法执行成功后调用通知;
异常通知(After-throwing):在目标方法抛出异常后调用通知;
环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
(3)切点
切点定义了通知在何处执行。切点和通知结合构成了一个完整的切面。
2、AOP具体实现
除了Spring的基础jar外,还需要额外导入aspectjweaver.jar,aopalliance.jar,aspectjrt.jar
(1)在XML中声明切面
定义一个接口IHelloWorldService :
package com.wygu.service; public interface IHelloWorldService { public void sayBefore(); public void sayAfter(); public boolean sayAfterReturning(); public void sayAfterThrow(); public void sayAround(); }
编写接口的实现HelloWorldService :
package com.wygu.impl; import com.wygu.service.IHelloWorldService; public class HelloWorldService implements IHelloWorldService{ @Override public void sayBefore() { System.out.println("Before Hello World!"); } @Override public void sayAfter() { System.out.println("After Hello World!"); } @Override public boolean sayAfterReturning() { System.out.println("After Returning Hello World!"); return true; } @Override public void sayAfterThrow() { System.out.println("After Throw Hello World!"); throw new RuntimeException("后置抛出异常"); } @Override public void sayAround() { System.out.println("Around Hello World!"); } }
定义切面HelloWorldAspect:
packa 1160d ge com.wygu.aop; import org.aspectj.lang.ProceedingJoinPoint; public class HelloWorldAspect { public void beforeAdvice(){ System.out.println("*******************前置通知"); } public void afterAdvice(){ System.out.println("*******************后置通知"); } public void afterReturnAdvice(Object retVal){ System.out.println("*******************返回通知"+":"+retVal); } public void afterThrowingAdvice(Exception exception){ System.out.println("*******************异常通知"); exception.printStackTrace(); } public void aroundAdvice(ProceedingJoinPoint pjp){ try { System.out.println("******************环绕之前通知"); //执行环绕方法 pjp.proceed(); System.out.println("******************环绕之后通知"); } catch (Throwable e) { e.printStackTrace(); System.out.println("******************执行环绕方法失败"); } } }
定义配置文件spring-aop.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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 定义Bean实例 --> <bean id="helloWorldService" class="com.wygu.impl.HelloWorldService"/> <!-- -定义切面Bean实例--> <bean id="helloAspect" class="com.wygu.aop.HelloWorldAspect"/> <aop:config> <!-- -声明切面 --> <aop:aspect id="ascept" ref="helloAspect"> <!-- -声明切点 --> <aop:pointcut id="pointcut1" expression="execution(* com.wygu.impl.*.sayBefore(..))" /> <aop:pointcut id="pointcut2" expression="execution(* com.wygu.impl.*.sayAfter(..))" /> <aop:pointcut id="pointcut3" expression="execution(* com.wygu.impl.*.sayAfterReturning(..))" /> <aop:pointcut id="pointcut4" expression="execution(* com.wygu.impl.*.sayAfterThrow(..))" /> <aop:pointcut id="pointcut5" expression="execution(* com.wygu.impl.*.sayAround(..))" /> <!-- -前置通知 --> <aop:before method="beforeAdvice" pointcut-ref="pointcut1"/> <!-- -后置通知 --> <aop:after method="afterAdvice" pointcut-ref="pointcut2" /> <!-- -后置返回通知 --> <aop:after-returning method="afterReturnAdvice" pointcut-ref="pointcut3" arg-names="retVal" returning="retVal" /> <!-- -后置异常通知 --> <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="pointcut4" arg-names="exception" throwing="exception" /> <!-- -环绕通知 --> <aop:around method="aroundAdvice" pointcut-ref="pointcut5"/> </aop:aspect> </aop:config> </beans>
程序测试:
package com.wygu.main; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.wygu.service.IHelloWorldService; public class TestAOP { public static void main(String[] args) throws InterruptedException { @SuppressWarnings("resource") ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop.xml"); IHelloWorldService helloWorldService = (IHelloWorldService) context.getBean("helloWorldService"); helloWorldService.sayBefore(); helloWorldService.sayAfter(); helloWorldService.sayAfterReturning(); try { helloWorldService.sayAfterThrow(); } catch (Exception e) { Thread.sleep(1000); } helloWorldService.sayAround(); } }
最终执行结果为:
八月 28, 2017 8:23:51 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@55801443: startup date [Mon Aug 28 20:23:51 GMT+08:00 2017]; root of context hierarchy 八月 28, 2017 8:23:51 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [spring-aop.xml] *******************前置通知 Before Hello World! After Hello World! *******************后置通知 After Returning Hello World! *******************返回通知:true After Throw Hello World! *******************异常通知 java.lang.RuntimeException: 后置抛出异常 at com.wygu.impl.HelloWorldService.sayAfterThrow(HelloWorldService.java:28) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy2.sayAfterThrow(Unknown Source) at com.wygu.main.TestAOP.main(TestAOP.java:18) ******************环绕之前通知 Around Hello World! ******************环绕之后通知
(2)使用注解创建切面
我们利用XML方式实现了AOP的五种通知类型,然而在实际开发中,使用比较多的还是利用注解的方式实现注入,下面利用注解实现切面的五种通知类型。
接口IHelloWorldService和接口的实现类HelloWorldService同上一个实例。
修改切面HelloWorldAspect
package com.wygu.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class HelloWorldAspect { @Before("execution(* com.wygu.impl.*.sayBefore(..))") public void beforeAdvice(){ System.out.println("*******************前置通知"); } @After("execution(* com.wygu.impl.*.sayAfter(..))") public void afterAdvice(){ System.out.println("*******************后置通知"); } @AfterReturning(value="execution(* com.wygu.impl.*.sayAfterReturning(..))", returning="retVal") public void afterReturnAdvice(Object retVal){ System.out.println("*******************返回通知"+":"+retVal); } @AfterThrowing(value="execution(* com.wygu.impl.*.sayAfterThrow(..))",throwing="exception" ) public void afterThrowingAdvice(Exception exception){ System.out.println("*******************异常通知"); exception.printStackTrace(); } @Around("execution(* com.wygu.impl.*.sayAround(..))") public void aroundAdvice(ProceedingJoinPoint pjp){ try { System.out.println("******************环绕之前通知"); //执行环绕方法 pjp.proceed(); System.out.println("******************环绕之后通知"); } catch (Throwable e) { e.printStackTrace(); System.out.println("******************执行环绕方法失败"); } } }
定义spring-aop.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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 启用AspectJ自动代理 --> <aop:aspectj-autoproxy /> <!-- 定义Bean实例 --> <bean id="helloWorldService" class="com.wygu.impl.HelloWorldService"/> <!-- -定义切面Bean实例--> <bean id="helloAspect" class="com.wygu.aop.HelloWorldAspect"/> </beans>
在xml中声明aspect的代理对象,使得在初始化spring 容器的时候,spring会自动对切点生成代理对象。如下:
<!-- 启用AspectJ自动代理 --> <aop:aspectj-autoproxy />
运行结果为:
*******************前置通知 Before Hello World! After Hello World! *******************后置通知 After Returning Hello World! *******************返回通知:true After Throw Hello World! *******************异常通知 java.lang.RuntimeException: 后置抛出异常 at com.wygu.impl.HelloWorldService.sayAfterThrow(HelloWorldService.java:28) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy10.sayAfterThrow(Unknown Source) at com.wygu.main.TestAOP.main(TestAOP.java:19) ******************环绕之前通知 Around Hello World! ******************环绕之后通知
相关文章推荐
- Spring.Net学习 控制反转(IoC)和面向切面编程(AOP) (转)
- Spring学习笔记 —— AOP(面向切面编程) 之使用ProxyFactoryBean实现AOP
- Spring学习之AOP(面向切面编程)
- Spring4第四讲学习笔记,AOP面向切面编程
- Spring学习三(AOP面向切面编程)
- Spring.Net学习 控制反转(IoC)和面向切面编程(AOP)
- Spring 学习(二) spring 面向切面编程(AOP)
- 【spring源码学习】spring的AOP面向切面编程的实现解析
- spring学习总结二-----面向切面编程(AOP)思想
- Spring学习(8)--AOP(面向切面编程)基础
- Spring学习之旅(二) AOP(面向切面编程)的使用
- Spring基础学习(八)——AOP面向切面编程
- Spring学习之深入AOP面向切面编程
- Spring学习笔记(AOP面向切面编程)
- Spring之注解实现aop(面向切面编程)
- Spring——aop(面向切面编程)
- SSH学习之——Spring面向方面编程AOP
- Spring之AOP(面向切面编程)
- Spring3.0 学习-AOP面向切面编程_Spring AOP的注解模式即Aspectj模式
- spring 中的aop面向切面编程