Spring AOP整理
2015-07-25 10:18
651 查看
AOP的概念很多,初次接触,不好接受,我们一点点来理解。
1. 通知(Advice)
通知定义了想要的功能,在何时使用,以及会干什么事情,自定义通知可以实现Spring中的五种通知,这五种通知下面会有介绍。
2. 连接点(JoinPoint)
连接点是spring允许你使用通知的地方,基本每个方法的前、后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点。
3. 切入点(PointCut)
切入点是在上面说的连接点的基础上来定义的,在一个类里,有15个方法,那么就有几十个连接点,但并不是想在所有方法附近都使用通知(使用叫织入),只想让其中的几个,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。
4. 切面(Aspect)
切面是通知和切入点的结合。没连接点什么事情,连接点是为了好理解切点,搞出来的。通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。
5. 引入(introduction)
引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)。
6. 目标(Target)
即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事),比如人是目标,他是关注我要睡觉这件事,至于睡前和睡后可以不用关心。
7. 代理(proxy)
应用通知的对象。
8. 织入(Weaving)
把切面应用到目标对象来创建新的代理对象的过程。
PS:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理是使用了JDK的动态代理技术,Spring提供了4种实现AOP的方式:
8.1.经典的基于代理的AOP 8.2.@AspectJ注解驱动的切面 8.3.纯POJO切面 8.4.注入式AspectJ切面
9. demo实践
首先看经典的基于代理的AOP,Spring支持五种类型的通知:
前置通知(MethodBeforeAdvice) 后置通知(AfterReturningAdvice) 包围通知(MethodIntercepter)
抛出通知(ThrowAdvice) 引入(IntroductionIntercepter)
这东西怎么玩?大概步骤:
1.创建通知:实现这几个接口,把其中的方法实现了
2.定义切点和通知者:在Spring配置文件中配置这些信息
3.使用ProxyFactoryBean来生成代理
9.1 程序1:
运行结果1:
9.2 程序2:其余不变,配置文件变换为context2.xml:
运行结果2:
9.3 程序3:配置文件变换为context3.xml,使用AspectJ提供的注解方式
运行结果3:
最后我们来看最后一种常用的实现AOP的方式:使用Spring来定义纯粹的POJO切面
前面我们用到了<aop:aspectj-autoproxy/>标签,Spring在aop的命名空间里面还提供了其他的配置元素:
我们用AOP标签来实现睡觉这个过程:代码不变,只是修改配置文件,加入AOP配置即可:
完!有需要补充的再继续在此版本上更改,程序附图:
1. 通知(Advice)
通知定义了想要的功能,在何时使用,以及会干什么事情,自定义通知可以实现Spring中的五种通知,这五种通知下面会有介绍。
2. 连接点(JoinPoint)
连接点是spring允许你使用通知的地方,基本每个方法的前、后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点。
3. 切入点(PointCut)
切入点是在上面说的连接点的基础上来定义的,在一个类里,有15个方法,那么就有几十个连接点,但并不是想在所有方法附近都使用通知(使用叫织入),只想让其中的几个,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。
4. 切面(Aspect)
切面是通知和切入点的结合。没连接点什么事情,连接点是为了好理解切点,搞出来的。通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。
5. 引入(introduction)
引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)。
6. 目标(Target)
即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事),比如人是目标,他是关注我要睡觉这件事,至于睡前和睡后可以不用关心。
7. 代理(proxy)
应用通知的对象。
8. 织入(Weaving)
把切面应用到目标对象来创建新的代理对象的过程。
PS:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理是使用了JDK的动态代理技术,Spring提供了4种实现AOP的方式:
8.1.经典的基于代理的AOP 8.2.@AspectJ注解驱动的切面 8.3.纯POJO切面 8.4.注入式AspectJ切面
9. demo实践
首先看经典的基于代理的AOP,Spring支持五种类型的通知:
前置通知(MethodBeforeAdvice) 后置通知(AfterReturningAdvice) 包围通知(MethodIntercepter)
抛出通知(ThrowAdvice) 引入(IntroductionIntercepter)
这东西怎么玩?大概步骤:
1.创建通知:实现这几个接口,把其中的方法实现了
2.定义切点和通知者:在Spring配置文件中配置这些信息
3.使用ProxyFactoryBean来生成代理
9.1 程序1:
/** * */ package test.spring.aop; /** * 具有睡觉能力的生物都可以实现该接口(不光生物,包括关机选项里面的休眠) * * @author quyang.ybb * */ public interface Sleepable { void sleep(); }
/** * */ package test.spring.aop.impl; import test.spring.aop.Sleepable; /** * 这是纯粹的睡觉(业务逻辑),睡觉前后会有一些辅助工作,如脱衣服、吃安眠药等,这些与纯粹的睡觉是不相干的 * * @author quyang.ybb * */ public class Human implements Sleepable { @Override public void sleep() { System.out.println("好累啊!终于可以睡觉了,谁也别吵我"); } }
/** * */ package test.spring.aop.help; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; import org.springframework.aop.MethodBeforeAdvice; /** * 里面包含了睡觉的辅助工作,用AOP术语来说它就应该是通知 * * @author quyang.ybb * */ public class SleepHelper implements MethodBeforeAdvice, AfterReturningAdvice { public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("睡觉前,我要把衣服脱掉,脱掉!"); } public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("起床后,我要把衣服穿上,穿上!"); } }
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:webflow="http://www.springframework.org/schema/webflow-config" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://img.alipay.net/dtd/schema/service http://img.alipay.net/dtd/schema/service/sofa-service.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd" default-autowire="byName"> <bean id="human" class="test.spring.aop.impl.Human"></bean> <!-- 睡觉帮助类,即通知 --> <bean id="sleepHelper" class="test.spring.aop.help.SleepHelper"></bean> <!-- pattern属性指定了正则表达式,它匹配所有的sleep方法 --> <bean id="sleepPointCut" class="org.springframework.aop.support.JdkRegexpMethodPointcut"> <property name="pattern" value=".*sleep"></property> </bean> <!-- 切点仅仅是定义了故事发生的地点,还有故事发生的时间以及最重要的故事的内容,就是通知了,我们需要把通知跟切点结合起来,即切面 --> <bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="pointcut" ref="sleepPointCut"></property> <property name="advice" ref="sleepHelper"></property> </bean> <!-- 切入点和通知都配置完成,接下来该调用ProxyFactoryBean产生代理对象了 --> <bean id="humanProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="human"></property> <property name="interceptorNames" value="sleepHelperAdvisor"></property> <property name="proxyInterfaces" value="test.spring.aop.Sleepable"></property> </bean> </beans>
package test.main; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import test.spring.aop.Sleepable; /** * 测试程序1 * @author quyang.ybb * */ public class MainTest { /** * @param args */ public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test/main/context.xml"); Sleepable sleeper = (Sleepable) applicationContext.getBean("humanProxy"); sleeper.sleep(); } }
运行结果1:
七月 25, 2015 10:11:32 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@4586787c: startup date [Sat Jul 25 10:11:32 CST 2015]; root of context hierarchy 七月 25, 2015 10:11:32 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [test/main/context.xml] 七月 25, 2015 10:11:33 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@771a1d97: defining beans [human,sleepHelper,sleepPointCut,sleepHelperAdvisor,humanProxy]; root of factory hierarchy 睡觉前,我要把衣服脱掉,脱掉! 好累啊!终于可以睡觉了,谁也别吵我 起床后,我要把衣服穿上,穿上!
9.2 程序2:其余不变,配置文件变换为context2.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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:webflow="http://www.springframework.org/schema/webflow-config" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://img.alipay.net/dtd/schema/service http://img.alipay.net/dtd/schema/service/sofa-service.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd" default-autowire="byName"> <!-- context.xml文件中配置切点跟通知过程有点复杂,Spring提供一种自动代理的功能,能让切点和通知自动匹配 --> <bean id="sleepHelper" class="test.spring.aop.help.SleepHelper"></bean> <bean id="sleepAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="sleepHelper"></property> <property name="pattern" value=".*sleep"></property> </bean> <bean id="human" class="test.spring.aop.impl.Human"></bean> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean> </beans>
package test.main; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import test.spring.aop.Sleepable; /** * 测试程序2 * @author quyang.ybb * */ public class MainTest2 { /** * @param args */ public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test/main/context2.xml"); Sleepable sleeper = (Sleepable) applicationContext.getBean("human"); sleeper.sleep(); } }
运行结果2:
七月 25, 2015 10:13:54 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7f50388c: startup date [Sat Jul 25 10:13:54 CST 2015]; root of context hierarchy 七月 25, 2015 10:13:54 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [test/main/context2.xml] 七月 25, 2015 10:13:55 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@462eab5b: defining beans [sleepHelper,sleepAdvisor,human,autoProxyCreator]; root of factory hierarchy 睡觉前,我要把衣服脱掉,脱掉! 好累啊!终于可以睡觉了,谁也别吵我 起床后,我要把衣服穿上,穿上!
9.3 程序3:配置文件变换为context3.xml,使用AspectJ提供的注解方式
/** * */ package test.spring.aop.help; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; /** * @author quyang.ybb * */ // 用@Aspect的注解来标识切面,注意不要把它漏了,否则Spring创建代理的时候会找不到 @Aspect public class SleepHelper3 { public SleepHelper3() { } // @Pointcut注解指定了切点 @Pointcut("execution(* *.sleep())") public void sleepPoint() { } // @Before指定了运行时的通知,注意的是要在注解中传入切点的名称 @Before("sleepPoint()") public void beforeSleep() { System.out.println("睡前我要看一会书"); } //@AfterReturning指定了运行时的通知,注意的是要在注解中传入切点的名称 @AfterReturning("sleepPoint()") public void afterSleep() { System.out.println("睡觉起来我要洗漱,收拾东西"); } }
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:webflow="http://www.springframework.org/schema/webflow-config" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://img.alipay.net/dtd/schema/service http://img.alipay.net/dtd/schema/service/sofa-service.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd"> <aop:aspectj-autoproxy /> <bean id="sleepHelper3" class="test.spring.aop.help.SleepHelper3"></bean> <bean id="human" class="test.spring.aop.impl.Human"></bean> </beans>
package test.main; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import test.spring.aop.Sleepable; /** * 测试程序3 * * @author quyang.ybb * */ public class MainTest3 { /** * @param args */ public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test/main/context3.xml"); Sleepable sleeper = (Sleepable) applicationContext.getBean("human"); sleeper.sleep(); } }
运行结果3:
七月 25, 2015 10:16:28 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7f50388c: startup date [Sat Jul 25 10:16:28 CST 2015]; root of context hierarchy 七月 25, 2015 10:16:28 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [test/main/context3.xml] 七月 25, 2015 10:16:29 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5740aa8a: defining beans [org.springframework.aop.config.internalAutoProxyCreator,sleepHelper3,human]; root of factory hierarchy 睡前我要看一会书 好累啊!终于可以睡觉了,谁也别吵我 睡觉起来我要洗漱,收拾东西
最后我们来看最后一种常用的实现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>
完!有需要补充的再继续在此版本上更改,程序附图:
相关文章推荐
- java序列化和反序列化
- java新手笔记13 继承
- Java学习笔记-------登录界面0
- JAVA 并发编程-多个线程之间共享数据(六)
- myeclipse8.5新建的maven项目变成web项目
- Java:IO流的一些典型例子
- java新手笔记12 单例
- 排序都有哪几种方法?请列举。用JAVA实现一个快速排序?
- Java 多线程(六) synchronized关键字详解
- @[Java]读取文件方法大全
- java新手笔记11 类的静态属性、方法(单例)
- java新手笔记10 构造器
- eclipse中配置maven
- eclipse中配置maven
- Java学习之路:详细解释Java解析XML四种方法
- java 产生的固体物的基础上 增删改的SQL声明
- [Domino]如何用java远程访问Domino邮箱数据
- spring task定时器的运用
- struts2基本介绍
- 10行Java代码实现最近被使用(LRU)缓存