SPRING_AOP_概念解析以及例子示范
Spring学习笔记五: AOP入门

Spring学习笔记五:AOP入门一、AOP术语切面(aspect):要实现的交叉功能,是系统模块化的一个切面或领域。
如日志记录。
连接点:应用程序执行过程中插入切面的地点,可以是方法调用,异常抛出,或者要修改的字段。
通知:切面的实际实现,他通知系统新的行为。
如在日志通知包含了实现日志功能的代码,如向日志文件写日志。
通知在连接点插入到应用系统中。
切入点:定义了通知应该应用在哪些连接点,通知可以应用到AOP框架支持的任何连接点。
引入:为类添加新方法和属性。
目标对象:被通知的对象。
既可以是你编写的类也可以是第三方类。
代理:将通知应用到目标对象后创建的对象,应用系统的其他部分不用为了支持代理对象而改变。
织入:将切面应用到目标对象从而创建一个新代理对象的过程。
织入发生在目标对象生命周期的多个点上:编译期:切面在目标对象编译时织入.这需要一个特殊的编译器.类装载期:切面在目标对象被载入JVM时织入.这需要一个特殊的类载入器.运行期:切面在应用系统运行时织入。
二、Spring AOP实现在spring中所有的通知都是以Java类的形式编写的。
切入点定义在配置文件中编写,所以切面代码和配置文件对我们来说都很熟悉。
对于其他框架(Aspectj),需要特定的语法编写,如果使用的话,还需学习新的语言。
spring的运行时通知对象spring在运行期创建代理,不需要特殊的编译器.spring有两种代理方式:若目标对象实现了若干接口,spring使用ng.reflect.Proxy类代理。
该类让spring 动态产生一个新类,它实现了所需的接口,织入了通知,并且代理对目标对象的所有请求。
若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
使用该方式时需要注意:2.1对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统。
对类代理是让遗留系统或无法实现接口的第三方类库同样可以得到通知,这种方式应该是备用方案。
Spring AOP技术

Spring AOP技术主要内容:1、AOP概述2、从代理机制初探AOP3、图解AOP术语4、Spring支持的增强5、Spring具体实现AOP技术1、AOP概述1.1 什么AOP?AOP,是Aspect Oriented Programming的缩写,意思是面向切面(方面)编程。
AOP是在实现业务处理阶段,降低代码(或模块)之间的耦合度。
AOP技术是通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态添加辅助功能的技术。
AOP的应用场合是受限的,它一般只适用于具有横切业务逻辑的应用场合,比如事务管理、日志管理、访问权限管理和性能监测管理等。
1.2 AOP理解从OOP和AOP两方面,考虑软件重构问题:面向对象编程OOP,如果在多个类当中出现过个相同的属性和方法时,考虑定义一个共同抽象类,将这些相同的代码抽取到抽象类中。
这种实现方式叫继承,纵向抽取重复代码。
查看下面一段代码:public void newStudent(Student s){ //权限验证操作checkQualify();//开始事务操作beginTransaction();//核心业务处理save(s);//结束事务--提交操作endTransaction();//添加日志操作log();} public void deleteStudent(Student s){ //权限验证操作checkQualify();//开始事务操作beginTransaction();/核心业务处理delete(s);//结束事务--提交操作endTransaction();/添加日志操作log();}考虑:代码里面存在重复代码,该怎么考虑重构?图1业务代码横向抽取将重复的横切业务逻辑从核心业务逻辑中提取出来封装到几个类中容易,但如何将这些抽取的逻辑在适当的时机融合到核心逻辑并形成完整的应用,这才是事情的关键,AOP就是解决这个问题。
Spring之AOP

【Spring之AOP】什么是AOP?-面向切面编程-它是一种思想,可在不改变程序源码的情况下为程序添加额外的功能。
-允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发。
应用对象只实现业务逻辑即可,并不负责其他的系统级关注点。
-AOP专门用于处理系统中分布于各个模块中的交叉关注点的问题,在J2EE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。
AOP的发展过程?-静态AOP:Aspect形式,通过特定的编译器,将实现后的Aspect编译并织入到系统的静态类中-动态AOP:AOP的织入过程在系统运行开始之后进行,而不是预先编译到系统中AOP术语?-连接点:程序执行的某个特定位置,比如类初始化前、类初始化后、方法调用前、方法调用后等-切点:通过切点来定位特定的连接点-增强:织入到目标类连接点上的一段程序代码-目标对象:增强逻辑的织入目标类-引介:是一种特殊的增强,它为类添加一些属性和方法-织入:为增强添加目标类的具体连接点上的过程-代理:一个类被AOP织入增强后,会产生一个结果类,该类融合了原类和增强逻辑的代理类-切面:由切点和增强组成,既包括了横切逻辑的定义,也包括了连接点的定义AOP的原理剖析?-AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用,AOP代理所包含的方法与目标对象的方法如下图所示:使用AOP的步骤是:定义普通业务组件--->定义切入点--->定义增强处理代理对象的方法= 增强处理+ 被代理对象的方法AOP的通俗理解?-一个组件A,不关心其他常用的服务组件B,但是这个组件A使用组件B的时候,不是组件A自身去调用,而是通过配置等其他方式,比如Spring中可以通过xml配置文件。
这样就使得A压根就不需要知道服务组件B是怎样的,爱存在不存在,爱怎么存在都与A无关。
spring中AOP注解开发示例详解

spring中AOP注解开发⽰例详解⼀、简介AOP主要包含了通知、切点和连接点等术语,介绍如下:通知(advice)通知定义了切⾯是什么以及何时调⽤,何时调⽤包含以下⼏种Before 在⽅法被调⽤之前调⽤通知After 在⽅法完成之后调⽤通知,⽆论⽅法执⾏是否成功After-returning 在⽅法成功执⾏之后调⽤通知After-throwing 在⽅法抛出异常后调⽤通知Around 通知包裹了被通知的⽅法,在被通知的⽅法调⽤之前和调⽤之后执⾏⾃定义的⾏为切点(PointCut)通知定义了切⾯的什么和何时,切点定义了何处,切点的定义会匹配通知所要织⼊的⼀个或多个连接点,我们通常使⽤明确的类的⽅法名称来指定这些切点,或是利⽤正则表达式定义匹配的类和⽅法名称来指定这些切点。
连接点(JoinPoint)连接点是在应⽤执⾏过程中能够插⼊切⾯的⼀个点,这个点可以是调⽤⽅法时,抛出异常时,甚⾄是修改⼀个字段时,切⾯代码可以利⽤这些连接点插⼊到应⽤的正常流程中,并添加新的⾏为,如⽇志、安全、事务、缓存等。
joinPoint.getSignature().getDeclaringTypeName() 可以获取到调⽤⽅法的类名(包括包名),joinPoint.getSignature().getName() 可以获取⽅法名,Arrays.toString(joinPoint.getArgs()) 得到的是⽅法调⽤的参数列表,joinPoint.proceed() 可以得到⽅法的返回结果⼆、注解开发声明⼀个切⾯,只需要在类名上添加@Aspect属性即可,具体的连接点,我们⽤@Pointcut和@Before、@After等标注。
在声明前我们需要依赖配置pom<dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.6.11</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.6.11</version></dependency>例⼦package com.ganji.demo.service.aspect;import ng.ProceedingJoinPoint;import ng.annotation.*;import org.springframework.stereotype.Service;/*** Created by admin on 2015/9/2.*/@Aspect@Servicepublic class XmlAopDemoUserLog {// 配置切点及要传的参数@Pointcut("execution(* erService.GetDemoUser(..)) && args(id)")public void pointCut(int id){}// 配置连接点⽅法开始执⾏时通知@Before("pointCut(id)")public void beforeLog(int id) {System.out.println("开始执⾏前置通知⽇志记录:"+id);}// ⽅法执⾏完后通知@After("pointCut(id)")public void afterLog(int id) {System.out.println("开始执⾏后置通知⽇志记录:"+id);}// 执⾏成功后通知@AfterReturning("pointCut(id)")public void afterReturningLog(int id) {System.out.println("⽅法成功执⾏后通知⽇志记录:"+id);}// 抛出异常后通知@AfterThrowing("pointCut(id)")public void afterThrowingLog(int id) {System.out.println("⽅法抛出异常后执⾏通知⽇志记录"+id);}// 环绕通知@Around("pointCut(id)")public Object aroundLog(ProceedingJoinPoint joinpoint,int id) {Object result = null;try {System.out.println("环绕通知开始⽇志记录"+id);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;}}AOP切⾯中的同步问题在WebLogAspect切⾯中,分别通过doBefore和doAfterReturning两个独⽴函数实现了切点头部和切点返回后执⾏的内容,若我们想统计请求的处理时间,就需要在doBefore处记录时间,并在doAfterReturning处通过当前时间与开始处记录的时间计算得到请求处理的消耗时间。
Spring学习教程(一):Spring中AOP基础

Spring学习教程(⼀):Spring中AOP基础Spring中AOP基础⼀、以⼀个例⼦引⼊1、例⼦描述:实现⼀个加减乘除的计算器,要求有⽇志,能给在程序执⾏期间追踪正在发⽣的活动。
2、代码⽰例:ArithmeticCalculator接⼝:package com.at.aop;public interface ArithmeticCalculator {int add(int i,int j);int sub(int i,int j);int mul(int i,int j);int div(int i,int j);}ArithmeticCalculator接⼝的实现类ArithmeticCalculatorLoggingImplpackage com.at.aop;public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {@Overridepublic int add(int i, int j) {System.out.println("add ⽅法输⼊参数是["+i+","+j+"]");int result = i + j;System.out.println("add ⽅法输出结果是"+result);return result;}@Overridepublic int sub(int i, int j) {System.out.println("sub ⽅法输⼊参数是["+i+","+j+"]");int result = i - j;System.out.println("sub ⽅法输出结果是"+result);return result;}@Overridepublic int mul(int i, int j) {System.out.println("mul ⽅法输⼊参数是["+i+","+j+"]");int result = i * j;System.out.println("mul ⽅法输出结果是"+result);return result;}@Overridepublic int div(int i, int j) {System.out.println("div ⽅法输⼊参数是["+i+","+j+"]");int result = i / j;System.out.println("div ⽅法输出结果是"+result);return result;}}测试函数package com.at.aop;public class TestArithmeticCalculator {public static void main(String[] args) {ArithmeticCalculator arithmeticCalculator = null;arithmeticCalculator = new ArithmeticCalculatorLoggingImpl();int result = arithmeticCalculator.add(1, 2);System.out.println(result);result = arithmeticCalculator.div(4, 2);System.out.println(result);}}运⾏结果:add ⽅法输⼊参数是[1,2]add ⽅法输出结果是33div ⽅法输⼊参数是[4,2]div ⽅法输出结果是223、例⼦总结(1)代码混乱:越来越多的⾮业务需求(⽇志和验证等)加⼊后, 原有的业务⽅法急剧膨胀。
通过代码实例跟我学面向方面编程从入门到精通——Spring框架中的AOP技术实现

杨教授工作室 精心创作的优秀程序员 职业提升必读系列资料
目标类的指定方法(见上面的黑体即为我们的 pointcut)运行时,LogInterceptor 即被触 发。 (2)advice(通知) 它就是我们想要向别的程序内部的不同的地方注入的程序代码。 Spring 中 采 用 了 AOP 联 盟 ( AOP Alliance ) 的 通 用 AOP 接 口 ( 接 口 定 义 在 aopalliance.jar 中) 。 我们只需要从 aopalliance.jar 中的某个接口来作为我们的 Advice 实现接口。下面给出一个代码示例。 package springaopapp; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import java.util.logging.*; public class LogInterceptor implements MethodInterceptor { private Logger logger = Logger.getLogger(this.getClass().getName()); public Object invoke(MethodInvocation methodInvocation) throws Throwable { logger.log(, methodInvocation.getMethod()); try { Object result = methodInvocation.proceed(); return result; } finally { logger.log(, methodInvocation.getMethod() + "\n"); } } }
SpringAOP的原理和应用场景
SpringAOP的原理和应用场景SpringAOP(Aspect-Oriented Programming)是Spring框架中的一个重要组成部分,它提供了一种通过预定义的方式,将横切关注点(Cross-cutting Concerns)与业务逻辑进行解耦的机制。
本文将介绍SpringAOP的原理及其在实际应用场景中的应用。
一、SpringAOP的原理SpringAOP基于代理模式(Proxy Pattern)实现。
在SpringAOP中,通过生成与原始类(被代理类)具有相同接口的代理类,将横切逻辑编织到业务逻辑中。
在运行时,当调用代理类的方法时,会在方法执行前、后或异常抛出时插入相应的横切逻辑代码。
具体而言,SpringAOP使用了以下几个核心概念:1. 切面(Aspect):切面是横切逻辑的模块化单元,它包含了一组通知(Advice)和切点(Pointcut)。
2. 通知(Advice):通知定义了实际的横切逻辑代码,并规定了何时执行该代码。
SpringAOP提供了五种类型的通知:前置通知(Before)、后置通知(After)、返回通知(After-returning)、异常通知(After-throwing)和环绕通知(Around)。
3. 切点(Pointcut):切点指定了在哪些连接点(Join Point)上执行通知。
连接点可以是方法调用、属性访问等程序执行的点。
4. 连接点(Join Point):连接点是程序执行过程中的一个特定点,如方法调用前、方法调用后等。
通知通过切点来选择连接点。
5. 织入(Weaving):织入是将切面应用到目标对象,并创建代理对象的过程。
织入可以在编译时、类加载时或运行时进行。
二、SpringAOP的应用场景SpringAOP可应用于各种场景,用于解决跨越多个模块或类的横切关注点问题。
以下是一些常见的SpringAOP应用场景:1. 日志记录:通过在关键方法的前后插入日志代码,实现对系统运行状态的监控和记录。
SpringBootAop详解和多种使用场景
SpringBootAop详解和多种使⽤场景前⾔aop⾯向切⾯编程,是编程中⼀个很重要的思想本篇⽂章主要介绍的是SpringBoot切⾯Aop的使⽤和案例什么是aopAOP(Aspect OrientedProgramming):⾯向切⾯编程,⾯向切⾯编程(也叫⾯向⽅⾯编程),是⽬前软件开发中的⼀个热点,也是Spring框架中的⼀个重要内容。
利⽤AOP可以对业务逻辑的各个部分进⾏隔离,从⽽使得业务逻辑各部分之间的耦合度降低,提⾼程序的可重⽤性,同时提⾼了开发的效率。
使⽤场景利⽤AOP可以对我们边缘业务进⾏隔离,降低⽆关业务逻辑耦合性。
提⾼程序的可重⽤性,同时提⾼了开发的效率。
⼀般⽤于⽇志记录,性能统计,安全控制,权限管理,事务处理,异常处理,资源池管理。
使⽤场景为什么需要⾯向切⾯编程⾯向对象编程(OOP)的好处是显⽽易见的,缺点也同样明显。
当需要为多个不具有继承关系的对象添加⼀个公共的⽅法的时候,例如⽇志记录、性能监控等,如果采⽤⾯向对象编程的⽅法,需要在每个对象⾥⾯都添加相同的⽅法,这样就产⽣了较⼤的重复⼯作量和⼤量的重复代码,不利于维护。
⾯向切⾯编程(AOP)是⾯向对象编程的补充,简单来说就是统⼀处理某⼀“切⾯”的问题的编程思想。
如果使⽤AOP的⽅式进⾏⽇志的记录和处理,所有的⽇志代码都集中于⼀处,不需要再每个⽅法⾥⾯都去添加,极⼤减少了重复代码。
技术要点通知(Advice)包含了需要⽤于多个应⽤对象的横切⾏为,完全听不懂,没关系,通俗⼀点说就是定义了“什么时候”和“做什么”。
连接点(Join Point)是程序执⾏过程中能够应⽤通知的所有点。
切点(Poincut)是定义了在“什么地⽅”进⾏切⼊,哪些连接点会得到通知。
显然,切点⼀定是连接点。
切⾯(Aspect)是通知和切点的结合。
通知和切点共同定义了切⾯的全部内容——是什么,何时,何地完成功能。
引⼊(Introduction)允许我们向现有的类中添加新⽅法或者属性。
SpringAOP示例与实现原理总结——传统springaop、基于切面注入、基于@Asp。。。
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中IOC和AOP的深入讲解
Spring中IOC和AOP的深⼊讲解前⾔Spring是⼀个开源框架,Spring是于2003 年兴起的⼀个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍⽣⽽来。
它是为了解决企业应⽤开发的复杂性⽽创建的。
Spring使⽤基本的JavaBean来完成以前只可能由EJB完成的事情。
然⽽,Spring的⽤途不仅限于服务器端的开发。
从简单性、可测试性和松耦合的⾓度⽽⾔,任何Java应⽤都可以从Spring中受益。
简单来说,Spring是⼀个轻量级的控制反转(IoC)和⾯向切⾯(AOP)的容器框架。
这篇⽂章主要讲 Spring 中的⼏个点,Spring 中的 IOC,AOP,下⼀篇说说 Spring 中的事务操作,注解和 XML 配置。
Spring 简介Spring 是⼀个开源的轻量级的企业级框架,其核⼼是反转控制 (IoC) 和⾯向切⾯ (AOP) 的容器框架。
我们可以把 Spring 看成是对象的容器,容器中可以包含很多对象,所以 Spring 有很多强⼤的功能。
⼀句话,Spring 是项⽬中对象的管家,负责管理项⽬中⽤到的所有对象。
所以在项⽬三层架构中,Spring 不属于某⼀特定层。
Spring 的 Hello World想要构建⼀个 Spring 的⼊门程序,我们需要导⼊ 4 个核⼼包和 2 个辅助包,创建⼀个实体类,最主要的是编写核⼼配置⽂件,applicationContext.xml 放在 src 下。
最后写⼀个测试类即可。
此时在测试类中我们不需要在使⽤ new 关键字去创建对象了。
这也正是 Spring 的作⽤所在,会⾃动给我创建对象。
上图展⽰的就是最基本的演⽰,也是很容易就理解了,配置⽂件中配置了 user 对象,我们通过加载配置⽂件来获取对象从⽽避免了使⽤ new 来创建。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
SPRING AOP 概念解析以及例子示范先了解AOP的相关术语:1.通知(Advice):通知定义了切面是什么以及何时使用。
描述了切面要完成的工作和何时需要执行这个工作。
2.连接点(Joinpoint):程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。
(before、after、around、throws)3.切入点(Pointcut)通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,Spring中允许我们方便的用正则表达式来指定4.切面(Aspect)通知和切入点共同组成了切面:时间、地点和要发生的“故事”5.引入(Introduction)引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)6.目标(Target)即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)7.代理(proxy)应用通知的对象,详细内容参见设计模式里面的代理模式8.织入(Weaving)把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术Spring提供了4种实现AOP的方式:1.经典的基于代理的AOP2.@AspectJ注解驱动的切面3.纯POJO切面4.注入式AspectJ切面首先看经典的基于代理的AOP:Spring支持五种类型的通知:Before(前) org.apringframework.aop.MethodBeforeAdviceAfter-returning(返回后) org.springframework.aop.AfterReturningAdviceAfter-throwing(抛出后) org.springframework.aop.ThrowsAdviceArround(周围) org.aopaliance.intercept.MethodInterceptorIntroduction(引入) org.springframework.aop.IntroductionInterceptor值的说明的是周围通知,他是由AOP Alliance中的接口定义的而非Spring,周围通知相当于前通知、返回后通知、抛出后通知的结合(传说中的完全体?好吧,我看日和看多了)还有引入通知怎么玩我还没搞清楚,等心无杂念的时候玩玩这东西怎么玩?这么几个步骤:1.创建通知:实现这几个接口,把其中的方法实现了2.定义切点和通知者:在Spring配制文件中配置这些信息3.使用ProxyFactoryBean来生成代理具体做法。
大晚上的就举个睡觉的例子吧:首先写一个接口叫Sleepable,这是一个牛X的接口,所有具有睡觉能力的东西都可以实现该接口(不光生物,包括关机选项里面的休眠)package test.spring.aop.beanpublic interface Sleepable{void sleep();}然后写一个Human类,他实现了这个接口package test.spring.aop.beanpublic Human implements Sleepable{/*这人莫非跟寡人差不多?*除了睡觉睡的比较好之外其余的什么也不会做?*/public void sleep(){System.out.println("睡觉了!梦中自有颜如玉!");}}好了,这是主角,不过睡觉前后要做些辅助工作的,最基本的是脱穿衣服,失眠的人还要吃安眠药什么的,但是这些动作与纯粹的睡觉这一“业务逻辑”是不相干的,如果把这些代码全部加入到sleep方法中,是不是有违单一职责呢?,这时候我们就需要AOP了。
编写一个SleepHelper类,它里面包含了睡觉的辅助工作,用AOP术语来说它就应该是通知了,我们需要实现上面的接口package test.spring.aop.bean;import ng.reflect.Method;import org.springframework.aop.AfterReturningAdvice;import org.springframework.aop.MethodBeforeAdvice;public class SleepHelper implements MethodBeforeAdvice,AfterReturningAdvice{public void before(Method mtd, Object[] arg1, Object arg2)throws Throwable {System.out.println("通常情况下睡觉之前要脱衣服!");}public void afterReturning(Object arg0, Method arg1, Object[] arg2,Object arg3) throws Throwable {System.out.println("起床后要先穿衣服!");}}然后在spring配置文件中进行配置:<bean id="sleepHelper" class="test.spring.aop.bean.SleepHelper"></bean>OK!现在创建通知的工作就完成了.第二步是进行配置,这是很令人蛋疼的操作,尤其是这么热的天,Spring又把东西的名字起的见鬼的长!它为啥不能像usr这种风格呢?首先要做的是配置一个切点,据说切点的表示方式在Spring中有好几种,但是常用的只有两种:1.使用正则表达式 2.使用AspectJ表达式 AspectJ我不是很熟悉(我也是熟悉党 or 精通党?),我还是习惯用正则表达式Spring使用org.springframework.aop.support.JdkRegexpMethodPointcut来定义正则表达式切点<bean id="spleepPointcut"class="org.springframework.aop.support.JdkRegexpMethodPointcut"><property name="pattern" value=".*sleep"/></bean>pattern属性指定了正则表达式,它匹配所有的sleep方法切点仅仅是定义了故事发生的地点,还有故事发生的时间以及最重要的故事的内容,就是通知了,我们需要把通知跟切点结合起来,我们要使用的通知者是:org.springframework.aop.support.DefaultPointcutAdvisor<bean id="sleepHelperAdvisor"class="org.springframework.aop.support.DefaultPointcutAdvisor"><property name="advice" ref="sleepHelper"/><property name="pointcut" ref="sleepPointcut"/></bean>切入点和通知都配置完成,接下来该调用ProxyFactoryBean产生代理对象了<bean id="humanProxy"class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="human"/><property name="interceptorNames" value="sleepHelperAdvisor" /><property name="proxyInterfaces" value="test.spring.aop.bean.Sleepable" /> </bean>ProxyFactoryBean是一个代理,我们可以把它转换为proxyInterfaces中指定的实现该interface的代理对象:import org.springframework.aop.framework.ProxyFactoryBean;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext; import test.spring.aop.bean.Sleepable;public class Test {public static void main(String[] args){ApplicationContext appCtx = newClassPathXmlApplicationContext("applicationContext.xml");Sleepable sleeper = (Sleepable)appCtx.getBean("humanProxy");sleeper.sleep();}}程序运行产生结果:通常情况下睡觉之前要脱衣服!睡觉啦~梦中自有颜如玉!起床后要先穿衣服!OK!这是我们想要的结果,但是上面这个过程貌似有点复杂,尤其是配置切点跟通知,Spring 提供了一种自动代理的功能,能让切点跟通知自动进行匹配,修改配置文件如下:<bean id="sleepHelper" class="test.spring.aop.bean.SleepHelper"></bean><bean id="sleepAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><property name="advice" ref="sleepHelper"/><property name="pattern" value=".*sleep"/></bean><bean id="human" class="test.spring.aop.bean.Human"></bean><beanclass="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreat or"/>执行程序:public class Test {public static void main(String[] args){ApplicationContext appCtx = newClassPathXmlApplicationContext("applicationContext.xml");Sleepable sleeper = (Sleepable)appCtx.getBean("human");sleeper.sleep();}}成功输出结果跟前面一样!只要我们声明了org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator(我勒个去的,名太长了)就能为方法匹配的bean自动创建代理!但是这样还是要有很多工作要做,有更简单的方式吗?有!一种方式是使用AspectJ提供的注解:package test.mine.spring.bean;import ng.annotation.AfterReturning;import ng.annotation.Aspect;import ng.annotation.Before;import ng.annotation.Pointcut;@Aspectpublic class SleepHelper {public SleepHelper(){}@Pointcut("execution(* *.sleep())")public void sleeppoint(){}@Before("sleeppoint()")public void beforeSleep(){System.out.println("睡觉前要脱衣服!");}@AfterReturning("sleeppoint()")public void afterSleep(){System.out.println("睡醒了要穿衣服!");}}用@Aspect的注解来标识切面,注意不要把它漏了,否则Spring创建代理的时候会找不到它,@Pointcut注解指定了切点,@Before和@AfterReturning指定了运行时的通知,注意的是要在注解中传入切点的名称然后我们在Spring配置文件上下点功夫,首先是增加AOP的XML命名空间和声明相关schema 命名空间:xmlns:aop="/schema/aop"schema声明:/schema/aop/schema/aop/spring-aop-2.0.xsd然后加上这个标签:<aop:aspectj-autoproxy/> 有了这个Spring就能够自动扫描被@Aspect标注的切面了最后是运行,很简单方便了:public class Test {public static void main(String[] args){ApplicationContext appCtx = newClassPathXmlApplicationContext("applicationContext.xml");Sleepable human = (Sleepable)appCtx.getBean("human");human.sleep();}}下面我们来看最后一种常用的实现AOP的方式:使用Spring来定义纯粹的POJO切面前面我们用到了<aop:aspectj-autoproxy/>标签,Spring在aop的命名空间里面还提供了其他的配置元素:<aop:advisor> 定义一个AOP通知者<aop:after> 后通知<aop:after-returning> 返回后通知<aop:after-throwing> 抛出后通知<aop:around> 周围通知<aop:aspect>定义一个切面<aop:before>前通知<aop:config>顶级配置元素,类似于<beans>这种东西<aop:pointcut>定义一个切点我们用AOP标签来实现睡觉这个过程:代码不变,只是修改配置文件,加入AOP配置即可:<aop:config><aop:aspect ref="sleepHelper"><aop:before method="beforeSleep" pointcut="execution(* *.sleep(..))"/> <aop:after method="afterSleep" pointcut="execution(* *.sleep(..))"/></aop:aspect></aop:config>完!OK~~基本上就这么多了吧,要想用好还得多折腾折腾,另外玩玩AspectJ~不就是个玩!。