spring AOP实现方法大全
- 格式:doc
- 大小:169.00 KB
- 文档页数:28
SpringAop注解实现⽬录Spring-aop-理论知识 Spring-Aop-注解实现项⽬结构图具体步骤:1、创建maven 项⽬导⼊依赖创建好项⽬结构2、写⼀个接⼝及其实现类3、切⾯类4、application.xml ⽂件测试总结Spring-aop-理论知识 Spring-Aop-注解实现项⽬结构图具体步骤:1、创建maven 项⽬导⼊依赖创建好项⽬结构<dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.18</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.4</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.3.4</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.3.4</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-expression</artifactId><version>5.3.4</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.4</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency></dependencies>2、写⼀个接⼝及其实现类/*** @version 1.0* @author: crush* @date: 2021-03-05 10:26*/public interface TestDao {public void delete();}/*** @version 1.0* @author: crush* @date: 2021-03-05 10:27*/@Servicepublic class TestDaoImpl implements TestDao {public void delete() {System.out.println("正在执⾏的⽅法-->删除");}}3、切⾯类/*** @version 1.0* @author: crush* @date: 2021-03-10 18:04*/@Aspect@Componentpublic class MyAspectAnnotation {@Pointcut("execution(* com.dao.*.*(..))")private void myPointCut(){}/*** 前置通知使⽤JoinPoint 接⼝作为参数获得⽬标对象的信息* @Before("myPointCut()") ==* <aop:after method="after" pointcut-ref="myPointCut"/>**/@Before("myPointCut()")public void before(JoinPoint jp){System.out.print("前置通知:模拟权限控制");System.out.println("⽬标对象:"+jp.getTarget()+",被增强的⽅法:"+jp.getSignature().getName()); }@AfterReturning("myPointCut()")public void afterReturning(JoinPoint jp){System.out.print("后置返回通知:"+"模拟删除临时⽂件");System.out.println(",被增强的⽅法"+jp.getSignature().getName());}@Around("myPointCut()")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("环绕开始:执⾏⽬标⽅法前,模拟开启事务");Object obj = pjp.proceed();System.out.println("环绕结束:执⾏⽬标⽅法后,模拟关闭事务");return obj;}@AfterThrowing(value = "myPointCut()",throwing = "throwable")public void except(Throwable throwable){System.out.println("异常通知:"+"程序执⾏异常"+throwable.getMessage());}@After("myPointCut()")public void after(){System.out.println("最终通知:释放资源");}}4、application.xml ⽂件<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/context/schema/context/spring-context.xsd /schema/aop https:///schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.dao"/><context:component-scan base-package="com.aspect"/><!--启动基于注解的AspectJ⽀持--><aop:aspectj-autoproxy proxy-target-class="true"/></beans>测试@Testpublic void Test(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");TestDao testDao = applicationContext.getBean("testDaoImpl", TestDaoImpl.class);testDao.delete();/*** 输出:* 环绕开始:执⾏⽬标⽅法前,模拟开启事务* 前置通知:模拟权限控制⽬标对象:com.dao.TestDaoImpl@2bef51f2,被增强的⽅法:delete* 正在执⾏的⽅法-->删除* 后置返回通知:模拟删除临时⽂件,被增强的⽅法delete* 最终通知:释放资源* 环绕结束:执⾏⽬标⽅法后,模拟关闭事务*/}总结本篇⽂章就到这⾥了,希望能给你带来帮助,也希望您能够多多关注的更多内容!。
JavaSpringAOP⽤法Java Spring AOP⽤法Spring AOPspring提供了两个核⼼功能,⼀个是IoC(控制反转),另外⼀个便是Aop(⾯向切⾯编程),IoC有助于应⽤对象之间的解耦,AOP则可以实现横切关注点(如⽇志、安全、缓存和事务管理)与他们所影响的对象之间的解耦。
1.简介AOP主要包含了通知、切点和连接点等术语,介绍如下通知(Advice)通知定义了切⾯是什么以及何时调⽤,何时调⽤包含以下⼏种Before 在⽅法被调⽤之前调⽤通知After 在⽅法完成之后调⽤通知,⽆论⽅法执⾏是否成功After-returning 在⽅法成功执⾏之后调⽤通知After-throwing 在⽅法抛出异常后调⽤通知Around 通知包裹了被通知的⽅法,在被通知的⽅法调⽤之前和调⽤之后执⾏⾃定义的⾏为切点(PointCut)通知定义了切⾯的什么和何时,切点定义了何处,切点的定义会匹配通知所要织⼊的⼀个或多个连接点,我们通常使⽤明确的类的⽅法名称来指定这些切点,或是利⽤正则表达式定义匹配的类和⽅法名称来指定这些切点。
切点的格式如下execution(* erService.GetDemoUser (..) )连接点(JoinPoint)连接点是在应⽤执⾏过程中能够插⼊切⾯的⼀个点,这个点可以是调⽤⽅法时,抛出异常时,甚⾄是修改⼀个字段时,切⾯代码可以利⽤这些连接点插⼊到应⽤的正常流程中,并添加新的⾏为,如⽇志、安全、事务、缓存等。
现阶段的AOP框架AOP框架除了之外,还包括、;上述框架的区别是Spring AOP只⽀持到⽅法连接点,另外两个还⽀持字段和构造器连接点。
2.⽤法同依赖注⼊⼀样,AOP在spring中有两种配置⽅式,⼀是xml配置的⽅式,⼆是⾃动注解的模式。
2.1 xml中声明切⾯2.1.1 AOP配置元素在xml中,我们使⽤如下AOP配置元素声明切⾯AOP配置元素 | 描述------------ | -------------`<aop:advisor>` | 定义AOP通知器`<aop:after>` | 定义AOP后置通知(不管该⽅法是否执⾏成功)`<aop:after-returning>` | 在⽅法成功执⾏后调⽤通知`<aop:after-throwing>` | 在⽅法抛出异常后调⽤通知`<aop:around>` | 定义AOP环绕通知`<aop:aspect>` | 定义切⾯`<aop:aspect-autoproxy>` | 定义`@AspectJ`注解驱动的切⾯`<aop:before>` | 定义AOP前置通知`<aop:config>` | 顶层的AOP配置元素,⼤多数的<aop:*>包含在<aop:config>元素内`<aop:declare-parent>` | 为被通知的对象引⼊额外的接⼝,并透明的实现`<aop:pointcut>` | 定义切点2.1.2 定义切⾯我们在service层添加com.ganji.demo.service.aspect.XmlAopDemoUserLog类,⾥⾯实现了拦截⽅法,具体如下package com.ganji.demo.service.aspect;import ng.ProceedingJoinPoint;/*** Created by admin on 2015/9/2.*/public class XmlAopDemoUserLog {// ⽅法执⾏前通知public void beforeLog() {System.out.println("开始执⾏前置通知⽇志记录");}// ⽅法执⾏完后通知public void afterLog() {System.out.println("开始执⾏后置通知⽇志记录");}// 执⾏成功后通知public void afterReturningLog() {System.out.println("⽅法成功执⾏后通知⽇志记录");}// 抛出异常后通知public void afterThrowingLog() {System.out.println("⽅法抛出异常后执⾏通知⽇志记录");}// 环绕通知public Object aroundLog(ProceedingJoinPoint joinpoint) {Object result = null;try {System.out.println("环绕通知开始⽇志记录");long start = System.currentTimeMillis();//有返回参数则需返回值result = joinpoint.proceed();long end = System.currentTimeMillis();System.out.println("总共执⾏时长" + (end - start) + " 毫秒");System.out.println("环绕通知结束⽇志记录");} catch (Throwable t) {System.out.println("出现错误");}return result;}}2.1.3 xml声明切⾯并调⽤我们在web层,web-inf/dispatcher-servlet.xml中定义切⾯,具体如下<!--定义切⾯指定拦截⽅法时做什么--><bean id="xmlAopDemoUserLog" class="com.ganji.demo.service.aspect.XmlAopDemoUserLog"></bean><aop:config><aop:aspect ref="xmlAopDemoUserLog"> <!--指定切⾯--><!--定义切点--><aop:pointcut id="logpoint" expression="execution(* erService.GetDemoUser(..))"></aop:pointcut><!--定义连接点--><aop:before pointcut-ref="logpoint" method="beforeLog"></aop:before><aop:after pointcut-ref="logpoint" method="afterLog"></aop:after><aop:after-returning pointcut-ref="logpoint" method="afterReturningLog"></aop:after-returning><aop:after-throwing pointcut-ref="logpoint" method="afterThrowingLog"></aop:after-throwing></aop:aspect></aop:config>在controller下调⽤,调⽤具体如下DemoUserEntity demoUser=userService.GetDemoUser(1);这是运⾏起来我们将看到打印出如下⽇志开始执⾏前置通知⽇志记录开始执⾏后置通知⽇志记录⽅法成功执⾏后通知⽇志记录2.1.4 ⼩结如果通过xml配置,我们还可以实现环绕通知,环绕通知的⽬的是把前置通知和后置通知的信息共享起来。
SpringAOP⽰例与实现原理总结——传统springaop、基于切⾯注⼊、基于@Asp。
⼀、代码实践1)经典的Spring Aop经典的spring aop,是基于动态代理技术的。
实现⽅式上,最常⽤的是实现MethodInterceptor接⼝来提供环绕通知,创建若⼲代理,然后使⽤ProxyBeanFactory配置⼯⼚bean,⽣成拦截器链,完成拦截。
⽰例如下:1package demo.spring;23import org.aopalliance.intercept.MethodInterceptor;4import org.aopalliance.intercept.MethodInvocation;5import org.junit.Test;6import org.junit.runner.RunWith;7import org.springframework.beans.factory.annotation.Autowired;8import org.springframework.test.context.ContextConfiguration;9import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;1011 @RunWith(SpringJUnit4ClassRunner.class)12 @ContextConfiguration("classpath:spring-config.xml")13public class TraditionalSpringAopDemo {14 @Autowired15private Service proxy;1617 @Test18public void test() {19 proxy.execute("hello world!");20 }21 }2223interface Service {24void execute(String str);25 }2627class ServiceImpl implements Service {28 @Override29public void execute(String str) {30 System.out.println("execute invoke: " + str);31 }32 }3334class Interceptor1 implements MethodInterceptor {35 @Override36public Object invoke(MethodInvocation methodInvocation) throws Throwable {37 System.out.println("interceptor1,before invoke");38 Object ret = methodInvocation.proceed();39 System.out.println("interceptor1,after invoke");40return ret;41 }42 }4344class Interceptor2 implements MethodInterceptor {45 @Override46public Object invoke(MethodInvocation methodInvocation) throws Throwable {47 System.out.println("interceptor2,before invoke");48 Object ret = methodInvocation.proceed();49 System.out.println("interceptor2,after invoke");50return ret;51 }52 }xml⽂件配置:1<?xml version="1.0" encoding="UTF-8"?>2<beans xmlns="/schema/beans"3 xmlns:xsi="/2001/XMLSchema-instance"4 xmlns:context="/schema/context"5 xmlns:aop="/schema/aop"6 xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd /schema/context /schema/context/sprin 78<context:component-scan base-package="demo.spring"/>910<bean class="demo.spring.ServiceImpl" id="service"></bean>11<bean class="demo.spring.Interceptor1" id="interceptor1"></bean>12<bean class="demo.spring.Interceptor2" id="interceptor2"></bean>13<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxy">14<property name="target" ref="service"/>15<property name="interceptorNames">16<list>17<value>interceptor1</value>18<value>interceptor2</value>19</list>20</property>21</bean>22</beans>结果:interceptor1,before invokeinterceptor2,before invokeexecute invoke: hello world!interceptor2,after invokeinterceptor1,after invoke可以看到拦截链的执⾏过程与拦截器顺序的关系。
Spring之注解实现aop(⾯向切⾯编程)1:Aop(aspect object programming)⾯向切⾯编程,名词解释:1.1:功能:让关注点代码与业务逻辑代码分离1.2:关注点重复代码就叫做关注点1.3:切⾯关注点形成的类,就叫做切⾯(类)⾯向切⾯编程,就是指对很多功能都有的重复代码抽取,再在运⾏的时候往业务⽅法上动态植⼊"切⾯类代码";1.4:切⼊点执⾏⽬标对象⽅法,动态植⼊切⾯代码可以通过切⼊点表达式,指定拦截那些类的那些⽅法,给指定的类在运⾏的时候植⼊切⾯类代码;2:注解⽅式实现aop编程2.1:开发步骤(1):先引⼊aop相关的jar⽂件spring-aop-3.2.5.RELEASE.jar【去spring3.2源码⾥⾯找】aopalliance.jar【去spring2.5源码/lib/aopalliance⽂件⾥⾯找】aspectjweaver.jar【去spring2.5源码/lib/aspectj⽂件⾥⾯找】或者【aspectj-1.8.2/lib/aspectjweaver.jar】aspectjrt.jar【去spring2.5源码/lib/aspectj⽂件⾥⾯找】或者【aspectj-1.8.2/lib/aspectjrt.jar】 《注意:⽤到的spring2.5版本的jar本舰,如果⽤jd1.7版本可能会出现问题,需要升级以下aspectj组件,即使⽤aspectj-1.8.2版本中提供的jar⽂件aspectjweaver.jar和aspectjrt.jar》(2)bean.xml中引⼊aop名称空间 技巧:找到⽂件spring-framework-3.2.5.RELEASE/docs/spring-framework-reference/htmlsingle 打开index.html搜索xmlns:aop然后找到下⾯红⾊三句话,分别拷贝到bean.xml中 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="/schema/beans" xmlns:xsi="/2001/XMLSchema-instance" xmlns:aop="/schema/aop" xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd /schema/aop /schema/aop/spring-aop.xsd"> 拷贝之后的bean.xml如下所⽰:1<?xml version="1.0" encoding="UTF-8"?>2<beans xmlns="/schema/beans"3 xmlns:xsi="/2001/XMLSchema-instance"4 xmlns:p="/schema/p"5 xmlns:context="/schema/context"6 xmlns:aop="/schema/aop"7 xsi:schemaLocation="8 /schema/beans9 /schema/beans/spring-beans.xsd10 /schema/context11 /schema/context/spring-context.xsd12 /schema/aop13 /schema/aop/spring-aop.xsd">1415</beans> (3):bean.xml中开启aop注解扫描,如下配置所⽰:1<?xml version="1.0" encoding="UTF-8"?>2<beans xmlns="/schema/beans"3 xmlns:xsi="/2001/XMLSchema-instance"4 xmlns:p="/schema/p"5 xmlns:context="/schema/context"6 xmlns:aop="/schema/aop"7 xsi:schemaLocation="8 /schema/beans9 /schema/beans/spring-beans.xsd10 /schema/context11 /schema/context/spring-context.xsd12 /schema/aop13 /schema/aop/spring-aop.xsd">1415<!-- 开启注解扫描 -->16<context:component-scan base-package="com.bie.aop"></context:component-scan>1718<!-- 开启aop注解⽅式,默认为false -->19<aop:aspectj-autoproxy></aop:aspectj-autoproxy>2021</beans> (4):开始写⼀个切⾯类,源码如下所⽰:1package com.bie.aop;23import ng.annotation.After;4import ng.annotation.Aspect;5import ng.annotation.Before;6import ng.annotation.Pointcut;7import ponent;8910/**11* @author BieHongLi12* @version创建时间:2017年3⽉28⽇下午9:10:4313* @Aspect:指定当前类为切⾯类14*/15 @Component //加⼊到IoC容器16 @Aspect //指定当前类为切⾯类17public class Aop {1819//指定切⼊点表达式,拦截那些⽅法,即为那些类⽣成代理对象20//@Pointcut("execution(* erDao.save(..))") ..代表所有参数21//@Pointcut("execution(* erDao.*())") 指定所有的⽅法22//@Pointcut("execution(* erDao.save())") 指定save⽅法2324 @Pointcut("execution(* erDao.*(..))")25public void pointCut(){2627 }2829 @Before("pointCut()")30public void begin(){31 System.out.println("开启事务");32 }3334 @After("pointCut()")35public void close(){36 System.out.println("关闭事务");37 }3839 } (5):写好切⾯类就可以写执⾏⽬标对象⽅法,接⼝和实现类如下所⽰: 1package com.bie.aop;23/**4* @author BieHongLi5* @version创建时间:2017年3⽉28⽇下午9:09:296*7*/89public interface IUserDao {1011public void save();12 }1package com.bie.aop;234import ponent;56/**7* @author BieHongLi8* @version创建时间:2017年3⽉28⽇下午9:09:539* ⽬标对象10*/11 @Component12public class UserDao implements IUserDao{1314 @Override15public void save() {16 System.out.println("..核⼼业务--核⼼业务..");17 }181920 } (6):最后就可以进⾏进⾏测试了,源码如下所⽰:1package com.bie.aop;23import org.junit.Test;4import org.springframework.context.ApplicationContext;5import org.springframework.context.support.ClassPathXmlApplicationContext;67/**8* @author BieHongLi9* @version创建时间:2017年3⽉28⽇下午9:13:1810*11*/12public class AopTest {1314 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");1516//⽬标对象有实现接⼝,spring会⾃动选择"jdk代理【动态代理】"17//动态代理的标识:class com.sun.proxy.$Proxy1018 @Test19public void test01(){20 IUserDao dao = (IUserDao) ac.getBean("userDao");21 System.out.println(dao.getClass());22 dao.save();23 }242526//class com.bie.aop.OrderDao$$EnhancerByCGLIB$$4952a60a27//⽬标对象没有实现接⼝,spring会⽤"cglib代理哦"28 @Test29public void testCglib(){30 OrderDao dao = (OrderDao) ac.getBean("orderDao");31 System.out.println(dao.getClass());32 dao.save();33 }34 } 3:⼼得体会和报错解决: 3.1:虽然案例很简单很简单,但是我花了三四个⼩时,为什么呢!我⽤junit测试spring写的注解实现aop(⾯向切⾯编程)。
AOP事务管理的原理与及三种实现方式AOP(Aspect-Oriented Programming)即面向切面编程,是一种软件开发方法,主要用于解决分散在一个应用程序中的横切关注点(cross-cutting concerns)问题。
事务管理是AOP的一个典型应用场景,它主要用于保证一系列操作的原子性、一致性和隔离性。
本文将详细介绍AOP事务管理的原理以及三种常见的实现方式。
一、AOP事务管理原理1.拦截器执行顺序首先,AOP框架通过拦截器机制,将事务相关的拦截器按照一定的顺序进行执行。
常见的拦截器有前置拦截器(Before)、后置拦截器(After)、异常拦截器(AfterThrowing)、返回拦截器(AfterReturning)等。
2.事务传播和隔离级别在方法级别的事务管理中,每个被拦截的方法可以有不同的事务传播行为和隔离级别。
事务传播行为指的是当一个方法调用另外一个方法时,如何处理事务;隔离级别指的是事务之间的隔离程度。
3.事务切面的应用通过拦截器机制,将事务注解或者配置文件中的事务属性传递给事务管理器,然后由事务管理器根据事务属性进行事务操作。
实际应用中,可以使用Spring框架提供的AOP事务管理功能来实现对方法级别的事务控制。
根据AOP事务管理的原理,常见的AOP事务管理的实现方式有基于注解的方式、基于XML配置的方式和基于编程的方式。
1.基于注解的方式优点:(1)简单方便,只需在方法上加上注解即可进行事务管理。
(2)灵活可控,通过注解可以更细粒度地控制事务的传播行为和隔离级别。
(3)清晰明了,注解能够直观地体现出事务的特性。
缺点:(1)侵入性较强,需要在代码中添加注解。
(2)不能对第三方库中的方法进行事务管理。
2.基于XML配置的方式基于XML配置的方式是通过在配置文件中定义事务管理器、事务通知以及切点表达式等信息,来实现对方法级别的事务控制。
通过AOP框架读取配置文件,将事务相关的信息应用到需要进行事务管理的方法上。
SpringAOP的⼏种实现⽅式总结AOP核⼼概念1、横切关注点对哪些⽅法进⾏拦截,拦截后怎么处理,这些关注点称之为横切关注点2、切⾯(aspect)类是对物体特征的抽象,切⾯就是对横切关注点的抽象3、连接点(joinpoint)被拦截到的点,因为spring只⽀持⽅法类型的连接点,所以在Spring中连接点指的就是被拦截到的⽅法,实际上连接点还可以是字段或者构造器4、切⼊点(pointcut)对连接点进⾏拦截的定义5、通知(advice)所谓通知指的就是指拦截到连接点之后要执⾏的代码,通知分为前置、后置、异常、最终、环绕通知五类6、⽬标对象代理的⽬标对象7、织⼊(weave)将切⾯应⽤到⽬标对象并导致代理对象创建的过程8、引⼊(introduction)在不修改代码的前提下,引⼊可以在运⾏期为类动态地添加⼀些⽅法或字段Spring 实现AOP所需要的包:1、Spring提供的jar包2、aopalliance.jar3、aspectjweaver.jarSpring 实现AOP的⽅式:1、Java动态代理该⽅法针对接⼝的实例创建代理applicationContext.xml的配置如下:<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:aop="/schema/aop"xmlns:tx="/schema/tx"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans-4.2.xsd/schema/aop/schema/aop/spring-aop-4.2.xsd"><bean id="concreteImplementor" class="com.marving.aop.ConcreteImplementor" /><bean id="interceptorHandler" class="com.marving.aop.InterceptorHandler" /><aop:config><aop:aspect id="interceptor" ref="interceptorHandler"><aop:pointcut id="addAllMethod" expression="execution(* com.marving.aop.Abstration.*(..))" /><aop:before method="doSomething" pointcut-ref="addAllMethod" /><aop:after method="doSomething" pointcut-ref="addAllMethod" /></aop:aspect></aop:config></beans>其中Abstration为接⼝,ConcreteImplementor为实现类,InterceptorHandler为代理拦截类。
SpringAOP的使⽤详解什么是AOPAOP(Aspect Oriented Programming ⾯向切⾯编程),通过预编译⽅式和运⾏期动态代理实现程序功能的统⼀维护的⼀种技术。
AOP是OOP的延续,是软件开发中的⼀个热点,也是Spring框架中的⼀个重要内容,是函数式编程的⼀种衍⽣范型。
利⽤AOP可以对业务逻辑的各个部分进⾏隔离,从⽽使得业务逻辑各部分之间的耦合度降低,提⾼程序的可重⽤性,同时提⾼了开发的效率。
常⽤于⽇志记录,性能统计,安全控制,事务处理,异常处理等等。
定义AOP术语切⾯(Aspect):切⾯是⼀个关注点的模块化,这个关注点可能是横切多个对象;连接点(Join Point):连接点是指在程序执⾏过程中某个特定的点,⽐如某⽅法调⽤的时候或者处理异常的时候;通知(Advice):指在切⾯的某个特定的连接点上执⾏的动作。
Spring切⾯可以应⽤5中通知:前置通知(Before):在⽬标⽅法或者说连接点被调⽤前执⾏的通知;后置通知(After):指在某个连接点完成后执⾏的通知;返回通知(After-returning):指在某个连接点成功执⾏之后执⾏的通知;异常通知(After-throwing):指在⽅法抛出异常后执⾏的通知;环绕通知(Around):指包围⼀个连接点通知,在被通知的⽅法调⽤之前和之后执⾏⾃定义的⽅法。
切点(Pointcut):指匹配连接点的断⾔。
通知与⼀个切⼊点表达式关联,并在满⾜这个切⼊的连接点上运⾏,例如:当执⾏某个特定的名称的⽅法。
引⼊(Introduction):引⼊也被称为内部类型声明,声明额外的⽅法或者某个类型的字段。
⽬标对象(Target Object):⽬标对象是被⼀个或者多个切⾯所通知的对象。
AOP代理(AOP Proxy):AOP代理是指AOP框架创建的对对象,⽤来实现切⾯契约(包括通知⽅法等功能)织⼊(Wearving):指把切⾯连接到其他应⽤出程序类型或者对象上,并创建⼀个被通知的对象。
SpringAOP注解⽅式实现简介上⽂已经提到了Spring AOP的概念以及简单的静态代理、动态代理简单⽰例,链接地址:h本⽂将介绍Spring AOP的常⽤注解以及注解形式实现动态代理的简单⽰例。
常⽤注解@aspect:定义切⾯@pointcut:定义切点@Before:前置通知,在⽅法执⾏之前执⾏@After:后置通知,在⽅法执⾏之后执⾏@AfterRunning:返回通知,在⽅法返回结果之后执⾏@AfterThrowing:异常通知,在⽅法抛出异常之后执⾏@Around:环绕通知,围绕着⽅法执⾏启动Spring AOP注解⾃动代理1. 在 classpath 下包含 AspectJ 类库:aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar2. 将 aop Schema 添加到 Bean 配置⽂件 <beans> 根元素中。
3. 在 Bean 配置⽂件中定义⼀个空的 XML 元素 <aop:aspectj-autoproxy proxy-target-class="true"/>(当 Spring IOC 容器检测到 Bean配置⽂件中的<aop:aspectj-autoproxy proxy-target-class="true"/> 元素时,会⾃动为与 AspectJ 切⾯匹配的 Bean 创建代理。
)代码⽰例1. 定义被代理类接⼝packege com.czr.aop.model;public interface superMan{//⾃我介绍public void introduce();}2. 定义被代理类packege com.czr.aop.model;@Component("superMan")public class SuperManImpl implements SuperMan {@overridepublic void introduce(){System.out.println("我是内裤外穿的超⼈");}}3. 定义切点类package com.czr.aop;import ng.ProceedingJoinPoint;import ng.annotation.After;import ng.annotation.Around;import ng.annotation.Aspect;import ng.annotation.Before;import ng.annotation.Pointcut;@Component("annotationAop")@Aspectpublic class AnnotationAop {//定义切点@Pointcut("execution(* com.czr.aop.model.*(..))")public void pointCutName(){}@Before("pointCutName()")public void beforeAdvice(){System.out.println("*注解前置通知实现*");}//后置通知@After("pointCutName()")public void afterAdvice(){System.out.println("*注解后置通知实现*");}//环绕通知。
Spring系列之AOP实现的两种⽅式Spring只⽀持XML⽅式⽽没有实现注解的⽅式(也叫AspectJ⽅式)的AOP,所以要使⽤@Aspect注解,只能引⼊AspectJ相关的 jar 包:aopalliance-1.0.jar 和 aspectjweaver.jarSpring的配置⽂件 applicationContext.xml 中引⼊context、aop对应的命名空间;配置⾃动扫描的包,同时使切⾯类中相关⽅法中的注解⽣效,需⾃动地为匹配到的⽅法所在的类⽣成代理对象。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:aop="/schema/aop"xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd/schema/aop /schema/aop/spring-aop-4.0.xsd/schema/context /schema/context/spring-context-4.0.xsd"><!-- 配置⾃动扫描的包 --><context:component-scan base-package="com.qcc.beans.aop"></context:component-scan><!-- ⾃动为切⾯⽅法中匹配的⽅法所在的类⽣成代理对象。
--><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>AOP常⽤的实现⽅式有两种,1、采⽤声明的⽅式来实现(基于XML),2、是采⽤注解的⽅式来实现(基于AspectJ)。
AOP实现(一)——Advice关键字: 初探aop在Spring1.2或之前的版本中,实现AOP的传统方式就是通过实现Spring的AOP API来定义Advice,并设置代理对象。
Spring根据Adivce加入到业务流程的时机的不同,提供了四种不同的Advice:Before Advice、After Advice、Around Advice、Throw Advice。
1、Before Advice顾名思义,Before Advice会在目标对象的方法执行之前被调用,您可以通过实现org.springframework.aop.MethodBeforeAdvice接口来实现Before Advice的逻辑,接口定义如下:java 代码1.package org.springframework.aop;2.3.public interface MethodBeforeAdvice extends BeforeAdvice {4. void before(Method method, Object[] args, Object target) throwsThrowable;5.}其中BeforeAdvice继承自Adivce接口,这两者都是标签接口,并没有定义任何具体的方法。
before方法会在目标对象的指定方法执行之前被执行,在before方法种,你可以取得指定方法的Method实例、参数列表和目标对象,在before方法执行完后,目标对象上的方法将会执行,除非在before方法种抛出异常。
下面通过例子来说明Before Advice的使用方法。
首先定义目标对象所要实现的接口:java 代码1.package com.savage.aop2.3.public interface MessageSender {4. void send(String message);5.}接着实现MessageSender接口:java 代码1.package com.savage.aop;2.3.public class HttpMessageSender implements MessageSender {4.public void send(String message) {5.System.out.println("Send Message[" + message + "] by http.");6.}7.}OK,我们的业务代码实现完了,现在如果要在不改变我们的业务代码的前提下,在执行业务代码前要记录一些日志,这时就可以通过实现MethodBeforeAdvice接口来实现,如:java 代码1.package com.savage.aop;2.3.import ng.reflect.Method;4.5.import org.springframework.aop.framework.MethodBeforeAdvice;6.7.public class LogBeforeAdvice implements MethodAdvice {8. public void before(Method method, Object[] args, Object target)throws Throwable {9. System.out.println("Log before " + method + " byLogBeforeAdvice.");10. }11.}然后再在XML进行如下定义:xml 代码1.<?xml version="1.0" encoding="UTF-8"?>2.<beans xmlns="/schema/beans"3.xmlns:xsi="/2001/XMLSchema-instance"4.xsi:schemaLocation="/schema/beans5./schema/beans/spring-beans-2.0.xsd">6.7. <bean id="messageSenderImpl" class="com.savage.aop.HttpMessageSender"></bean>8.9. <bean id="logBeforeAdvice" class="com.savage.aop.LogBeforeAdvice"></bean>10.11. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">12. <property name="proxyInterfaces" value="com.savage.aop.MessageSender"/>13. <property name="target" ref="messageSenderImpl"/>14. <property name="interceptorNames">15. <list>16. <value>logBeforeAdvice</value>17. </list>18. </property>19. </bean>20.</beans>这样我们就为MessageSender对象指定了Before Advice对象。
在这里,我们分别定义了一个MessageSender对象(messageSenderImpl)和一个Before Advice对象(logBeforeAdvice),并定义了一个org.springframework.aop.framework.ProxyFactoryBean对象(messageSender),FactoryBean或ApplicationContext将使用ProxyFactoryBean来建立代理对象,在这里就是messageSenderImpl建立代理对象。
在ProxyFactoryBean的定义中,proxyInterfaces属性指定了要代理的接口;target指定了要建立代理的目标对象;interceptorNames则指定了应用与指定接口上的Advices对象列表,spring将根据列表中定义的顺序在执行目标对象的方法前、后执行Advice中定义的方法。
现在我们写一个程序来验证下:java 代码1.package com.savage.aop;2.3.import org.springframework.context.ApplicationContext;4.importorg.springframework.context.support.ClassPathXmlApplication;5.6.public class AdviceDemo {7. public void main(String[] args) {8. ApplicationContext context = newClassPathXmlApplicationContext("beans-config.xml");9. MessageSender sender =(MessageSender)context.getBean("messageSender");10. sender.send("message");11. }12.}执行结果:Log before public abstract voidcom.savage.simplespring.bean.MessageSender.send(ng.String) by LogBeforeAdvice.Send Message[message] by http.正如你所看到的,在执行MessageSender的send方法前先执行了LogBeforeAdvice的方法!在这个例子中,记录日志的代码并没有横切到我们的业务代码中,LogBeforeAdvice和HttpMessageSender彼此不知道对方的存在,而且我们的应用程序AdviceDemo对LogBeforeAdvice的存在也是一无所知。
假如有一天我们的应用程序不需要再业务代码执行前记录日志了,只需要修改XML文件中的定义,而不用更改AdviceDemo的代码:xml 代码1.<bean id="messageSender"class="com.savage.aop.HttpMessageSender">bean>2、After AdviceAfter Advice会在目标对象的方法执行完后执行,你可以通过实现org.springframework.aop.AfterReturingAdvice接口来实现After Advice的逻辑,AfterReturingAdvice接口定义如下:java 代码1.package org.springframework.aop;2.3.public interface AfterReturningAdvice {4. void afterReturning(Object returnValue, Method method,Object[] args, Object target) throws Throwable;5.}在afterReturning方法中,你可以获得目标方法执行后的返回值、目标方法对象、目标方法的参数以及目标对象。
继续以上面的例子为例,如果要在MessageSender的send方法执行完后,要再记录日志,那么我们可以先实现AfterReturningAdvice接口:java 代码1.package com.savage.aop;2.3.import org.springframework.aop;4.5.public LogAfterAdvice implements AfterReturningAdvice {6. public void afterReturning(Object returnValue, Methodmethod, Object[] args, Object target) throws Throwable {7. System.out.println("Log after " + method + " byLogAfterAdvice.");8. }9.}然后在XML文件中指定LogAfterAdvice的实例:xml 代码1.<?xml version="1.0" encoding="UTF-8"?>2.<beans xmlns="/schema/beans"3.xmlns:xsi="/2001/XMLSchema-instance"4.xsi:schemaLocation="/schema/beans5./schema/beans/spring-beans-2.0.xsd">6.7. <bean id="messageSenderImpl" class="com.savage.aop.HttpMessageSender"></bean>8.9. <bean id="logBeforeAdvice" class="com.savage.aop.LogBeforeAdvice"></bean>10.11. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">12. <property name="proxyInterfaces" value="com.savage.aop.MessageSender"/>13. <property name="target" ref="messageSenderImpl"/>14. <property name="interceptorNames">15. <list>16. <value>logAfterAdvice</value>17. </list>18. </property>19. </bean>20.</beans>在前面Before Advice的基础上,我们为MessageSender再指定了一个LogAfterAdvice的服务。