Spring的AOP
来源:互联网 发布:女生必知护肤技巧少女 编辑:程序博客网 时间:2024/06/06 02:19
AOP的术语与概念
1.横切关注点Cross-cutting concern
一个用户方法在一个应用程序中常被安排到各个处理流程中,这些方法在AOP的术语中称为横切关注点。
2.横切关注面Aspect
将散落在各个业务中的横切关注点收集起来,设计为各个独立可重用的类,这种类称为横切关注面(Aspect)。
3.连接点Join point
连接点是指程序中的某一个点。AspectJ中的连接点主要有如下形式:
-方法调用:方法被调用时。
-方法执行:方法体的内容执行时。
-构造方法调用:构造方法被调用时。
-构造方法执行:构造方法体的内容执行时。
-静态初始化部分执行:类中的静态部分内容初始化时。
-对象预初始化:主要指执行构造方法中的this()及super()时。
-对象初始化:在初始化一个类时。
-属性引用:引用属性时。
-属性设置:设置属性时。
-异常执行:异常执行时。
-通知执行:当一个AOP通知执行时。
连接点使用系统提供的关键字来表示。连接点不能单独存在,需要与一定的上下文结合。
4.切入点Pointcuts
切入点是连接点的集合,tasteful程序中需要注入Advice的位置的集合,指明Advice要在什么条件下被触发。
5.通知Advice
通知定义了切面中的实际实现,是指在定义好的切入点出执行的程序代码。在Spring中提供了四种通知类型:Before Advice、After Advice、Around Advice、Throw Advice。
6.拦截器Interceptor
拦截器用来实现对连接点进行拦截,从而在连接点前后加入自定义的切面模块功能。在大多数的Java的AOP框架中,基本上都是用拦截器来实现字段访问及方法调用的拦截。
7.目标对象Target object
目标对象是指在基本拦截器机制实现的AOP框架中,位于拦截器链上最末端的对象实例。一般情况下,拦截器末端包含的目标对象就是实际业务对象。
Spring1.x的AOP支持
Spring1.x的AOP支持,它主要针对不同类型的拦截使用XML配置文件通过代理来完成,有4种通知:前置通知、后置通知、环绕通知、异常通知。
1.前置通知 Before Advice
在目标对象方法执行前被调用,应用前置通知需先设计一个借口,然后编写这个接口的实现类,接着编写前置通知的逻辑代码,该代码需实现MethodBeforeAdvice接口,并覆盖其before()方法,该逻辑代码主要编写一些需要前置的服务,最后通过配置XML文件来实现AOP的前置通知。
(1)定义接口
package org.aop.interfaces;public interface IHello { public void sayHello1(); public void sayHello2(); public void sayHello3();}
(2)接口实现类
package org.aop.interfaces.impl;import org.aop.interfaces.IHello;public class Hello implements IHello{ @Override public void sayHello1() { // TODO Auto-generated method stub System.out.print("Hello~1"); } @Override public void sayHello2() { // TODO Auto-generated method stub System.out.print("Hello~2"); } @Override public void sayHello3() { // TODO Auto-generated method stub System.out.print("Hello~3"); }}
(3)实现前置通知类
该类需实现MethodBeforeAdvice接口,并覆盖其before(方法)。
package org.aop.advice;import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;public class AdviceBeforeHello implements MethodBeforeAdvice{ @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { // TODO Auto-generated method stub System.out.print("前置验证用户..."); }}
(4)配置前置通知
修改applicationContext.xml文件,添加如下内容
<!-- 注册前置通知类 --> <bean id="beforeAdvice" class="org.aop.advice.AdviceBeforeHello"/> <!-- 注册代理类 --> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 指定应用的接口 --> <property name="proxyInterfaces"> <value>org.aop.interfaces.IHello</value> </property> <!-- 目标对象,本例中为Hello对象 --> <property name="target" ref="hello"></property> <!-- 应用的前置通知,拦截去名称 --> <property name="interceptorNames"> <list> <value>beforeAdvice</value> </list> </property> </bean> <!-- 注册接口实现类 --> <bean id="hello" class="org.aop.interfaces.impl.Hello"/>
(5)测试程序
package test;import org.aop.interfaces.IHello;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test { public static void main(String[] args) { // TODO Auto-generated method stub //ClassPathXmlApplicationContext会从ClassPath中寻找支配文件applicationContext.xml ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); IHello hello = (IHello) ac.getBean("proxy"); hello.sayHello1(); hello.sayHello2(); hello.sayHello3(); }}
运行结果:
2.后置通知 AfterAdvice
后置通知与前置通知相似,不同的是在目标对象的方法执行完成后才被调用,后置通知的逻辑代码需实现AfterReturningAdvice接口,并覆盖其afterReturning()方法。
(1)接口为IHello,接口实现类为Hello(见上文)。
(2)实现后置通知类
package org.aop.advice;import java.lang.reflect.Method;import org.springframework.aop.AfterReturningAdvice;public class AdviceAfterHello implements AfterReturningAdvice { @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { // TODO Auto-generated method stub System.out.print("后置验证用户..."); }}
(3)修改配置文件
<!-- 注册后置通知类 --> <bean id="afterAdvice" class="org.aop.advice.AdviceAfterHello"/> <!-- 注册代理类 --> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 指定应用的接口 --> <property name="proxyInterfaces"> <value>org.aop.interfaces.IHello</value> </property> <!-- 目标对象,本例中为Hello对象 --> <property name="target" ref="hello"></property> <!-- 应用的后置通知,拦截去名称 --> <property name="interceptorNames"> <list> <value>afterAdvice</value> </list> </property> </bean> <!-- 注册接口实现类 --> <bean id="hello" class="org.aop.interfaces.impl.Hello"/>
(4)测试运行
3.环绕通知 Around Advice
环绕通知相当与前置通知和后置通知的结合使用,建立一个环绕通知需实现MethodInterceptor接口,并覆盖其invoke()方法。
(1)接口为IHello,接口实现类为Hello(见上文)。
(2)实现环绕通知类
package org.aop.advice;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;public class AdviceAroundHello implements MethodInterceptor { @Override public Object invoke(MethodInvocation arg0) throws Throwable { // TODO Auto-generated method stub System.out.print("前置验证用户..."); Object result = null; try{ result = arg0.proceed(); } finally{ System.out.print("后置验证用户"); } return result; }}
该程序调用了methodInvocation方法的preceed方法,即调用了目标对象Hello的sayHello*()等一些方法,在这个方法后面分别添加验证。
(3)修改配置文件
<!-- 注册环绕通知类 --> <bean id="rondAdvice" class="org.aop.advice.AdviceAroundHello"/> <!-- 注册代理类 --> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 指定应用的接口 --> <property name="proxyInterfaces"> <value>org.aop.interfaces.IHello</value> </property> <!-- 目标对象,本例中为Hello对象 --> <property name="target" ref="hello"></property> <!-- 应用的环绕通知,拦截去名称 --> <property name="interceptorNames"> <list> <value>rondAdvice</value> </list> </property> </bean> <!-- 注册接口实现类 --> <bean id="hello" class="org.aop.interfaces.impl.Hello"/>
(4)测试运行
4.异常通知 Throw Advice
异常通知就是程序发送异常时执行相关的服务。为造成异常发送,可以人为抛出异常用于演示。
(1)定义接口
package org.aop.interfaces;public interface IHelloException { public void sayHello1()throws Throwable; public void sayHello2()throws Throwable; public void sayHello3()throws Throwable;}
(2)实现异常通知类
package org.aop.interfaces.impl;import org.aop.interfaces.IHelloException;public class HelloException implements IHelloException { @Override public void sayHello1() throws Throwable { // TODO Auto-generated method stub System.out.println("SayHello1..."); throw new Exception("异常"); } @Override public void sayHello2() throws Throwable{ // TODO Auto-generated method stub System.out.print("SayHello1..."); throw new Exception("异常"); } @Override public void sayHello3() throws Throwable{ // TODO Auto-generated method stub System.out.print("SayHello1..."); throw new Exception("异常"); }}
(3)实现异常通知类
package org.aop.advice;import org.springframework.aop.ThrowsAdvice;public class AdviceThrow implements ThrowsAdvice { public void afterThrowing(Throwable throwable){ System.out.println("有异常抛出。。。。"); }}
(4)修改配置文件
<!-- 注册异常通知类 --> <bean id="exceptionAdvice" class="org.aop.advice.AdviceThrow"/> <!-- 注册代理类 --> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 指定应用的接口 --> <property name="proxyInterfaces"> <value>org.aop.interfaces.IHelloException</value> </property> <!-- 目标对象,本例中为Hello对象 --> <property name="target" ref="hello"></property> <!-- 应用的异常通知,拦截去名称 --> <property name="interceptorNames"> <list> <value>exceptionAdvice</value> </list> </property> </bean> <!-- 注册接口实现类 --> <bean id="hello" class="org.aop.interfaces.impl.HelloException"/>
(5)测试运行
package test;import org.aop.interfaces.IHello;import org.aop.interfaces.IHelloException;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test { public static void main(String[] args) { // TODO Auto-generated method stub //ClassPathXmlApplicationContext会从ClassPath中寻找支配文件applicationContext.xml ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); IHelloException hello = (IHelloException) ac.getBean("proxy"); try { hello.sayHello1(); hello.sayHello2(); hello.sayHello3(); } catch (Throwable e) { // TODO Auto-generated catch block System.out.print(e); } }}
运行结果:
5.NameMatchMethodPointAdvisor
可通过NameMatchMethodPointcutAdvisor,对指定的方法调用通知。
(1)接口为IHello,实现类为Hello,调用通知类为AdviceBeforeHello;
(2)修改配置文件
<!-- 注册前置通知类 --> <bean id="beforeAdvice" class="org.aop.advice.AdviceBeforeHello"/> <!-- 注册NameMathMethodPointAdvisor的Bean --> <bean id="helloAdvice" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <!-- 配置要执行通知的方法 --> <property name="mappedName" value="*2"></property> <!-- 指定使用的通知类,此处为前置通知 --> <property name="advice" ref="beforeAdvice"></property> </bean> <!-- 注册代理类 --> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 指定应用的接口 --> <property name="proxyInterfaces"> <value>org.aop.interfaces.IHello</value> </property> <!-- 目标对象,本例中为Hello对象 --> <property name="target" ref="hello"></property> <!-- 应用的异常通知,拦截去名称 --> <property name="interceptorNames"> <list> <value>helloAdvice</value> </list> </property> </bean> <!-- 注册接口实现类 --> <bean id="hello" class="org.aop.interfaces.impl.Hello"/>
(3)测试运行
6.RegexpMethodPointAdvisor
实现同NameMatchMethodPointcutAdvisor,对指定方法,调用通知。
(1)接口为IHello,实现类为Hello,调用通知类为AdviceBeforeHello;
(2)修改配置文件
<!-- 注册前置通知类 --> <bean id="beforeAdvice" class="org.aop.advice.AdviceBeforeHello"/> <!-- 注册NameMathMethodPointAdvisor的Bean --> <bean id="reExpAdvice" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!-- 配置要执行通知的方法 --> <property name="pattern" value=".*2"></property> <!-- 指定使用的通知类,此处为前置通知 --> <property name="advice" ref="beforeAdvice"></property> </bean> <!-- 注册代理类 --> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 指定应用的接口 --> <property name="proxyInterfaces"> <value>org.aop.interfaces.IHello</value> </property> <!-- 目标对象,本例中为Hello对象 --> <property name="target" ref="hello"></property> <!-- 应用的异常通知,拦截去名称 --> <property name="interceptorNames"> <list> <value>reExpAdvice</value> </list> </property> </bean> <!-- 注册接口实现类 --> <bean id="hello" class="org.aop.interfaces.impl.Hello"/>
(3)测试运行
Spring2.x的AOP支持
在Spring2.x除了支持Spring1.x的AOP支持外,还提供了如下两种实现AOP方式。
-基于XML的配置,使用基于Schema的XML配置来完成AOP,并且Advice不用再实现任何其他特定接口。
-使用JDK5的注释来完成AOP的实现,只需一个简单的标签即可完成AOP的整个过程。
1.基于XML Schema的前置通知
改写Spring1.x的前置通知例子,完成应用XML Scheme的前置通知。
(1)前置通知逻辑代码
package org.aop.advice;public class AdviceBeforeHello{ public void before(){ System.out.print("前置验证用户..."); }}
(2)修改Spring核心配置文件application.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:aop="http://www.springframework.org/schema/aop"** xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd **http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd**"> <!-- 注册前置通知类 --> <bean id="beforeAdvice" class="org.aop.advice.AdviceBeforeHello"/> **<!-- 定义aop:config --> <aop:config> <aop:pointcut id="beforePointcut" expression="execution(* org.aop.interfaces.IHello.*(..))"/> <aop:aspect id="before" ref="beforeAdvice"> <aop:before pointcut-ref="beforePointcut" method="before"/> </aop:aspect> </aop:config>** <!-- 注册接口实现类 --> <bean id="hello" class="org.aop.interfaces.impl.Hello"/></beans>
在配置文件Beans的属性中加入了schema的命名空间:
xmlns:aop="http://www.springframework.org/schema/aop"http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
然后,配置<aop:config>
标签来配置一个aop片段,其配置规则为:
<aop:config> <aop:pointcut id="pointcutName" expression="匹配的正则表达式"/> <aop:advisor id="AdvisorName" pointcut-ref="pointcut的Bean Id"> <aop:aspect id="aspectName" ref="songBean"> <aop:adviceType pointcut-ref="应用的poincutName" method="methodName"/> </aop:aspect></aop:config>
配置内容:
-<aop:pointcut>
:用来配置AOP的正则表达式,其他标签可以直接根据标签的id属性来引用。
注:在配置表达式是,“*”与后面的接口间要有一个空格。
-<aop:advisor>
:用来配置AOP的切面,与pointcut相同,可以直接使用advisor的id来引用该切面。
-<aop:aspect>
:用来配置一个切面,ref指定要应用的通知类,<aop:adviceType>
用来配置通知的类型,可以是<aop:before>
前置通知,<aop:after>
后置通知,<aop:around>
环绕通知,<aop:after-throwing>
异常通知,pointcut-ref属性来引用一个pointcut,method属性用来指定要应用的通知类中的方法。
(3)编写测试类
package test;import org.aop.interfaces.IHello;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test { public static void main(String[] args) { // TODO Auto-generated method stub //ClassPathXmlApplicationContext会从ClassPath中寻找支配文件applicationContext.xml ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); IHello hello = (IHello) ac.getBean("hello"); hello.sayHello1(); hello.sayHello2(); hello.sayHello3(); }}
2.基于XML Schema的后置通知
基本思路与前置通知一样。
3.基于XML Schema的环绕通知
基本思路与前置通知一样。
其中后置通知类为:
package org.aop.advice;import org.aspectj.lang.ProceedingJoinPoint;public class AdviceAroundHello{ public Object around(ProceedingJoinPoint joinPoint) throws Throwable { // TODO Auto-generated method stub System.out.print("前置验证用户..."); Object result = joinPoint.proceed(); System.out.print("后置验证用户"); return result; }}
4.基于XML Schema的异常通知
思路与前置通知一样。
5.基于Annotation的前置通知
Spring2.x结合JDK 5及以上版本,提供了Annotation设置AOP通知,对AOP实现大大简化。
(1)修改通知类
package org.aop.advice;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspectpublic class AdviceBeforeHello{ @Before("execution(* org.aop.interfaces.IHello.*(..))") public void before(){ System.out.print("前置验证用户..."); }}
使用@Aspect标签表示该类是一个Aspect
使用@Before标签表示该方法是一个前置通知,里面的”execution(* org.aop.interfaces.IHello.*(..))”为正则表达式。
6..基于Annotation的后置通知、环绕通知、异常通知
思路与前置通知一样。
与@Before相对应改为:@AfterReturning,@Around,@AfterThrowing。
- AOP、Spring的AOP
- spring(AOP)Aop的概念
- spring的的AOP
- Spring的AOP实现
- spring的AOP介绍
- Spring的aop
- 6.2 Spring的AOP
- Spring 的AOP运用
- spring aop的理解
- spring aop的讲解
- spring的aop原理
- spring的aop
- spring的AOP配置
- Spring AOP的应用
- Spring的AOP
- Spring的AOP配置
- Spring的aop
- Spring Aop的应用
- 从上下文无关文法(CFG)到语法分析树——LL(1)分析法
- Codeforces Round #332 (Div. 2) E
- C语言经典题-库函数strlen与strcpy工作方式
- Datagrid 与Treegrid的查询问题
- BZOJ 4561 [JLoi2016]圆的异或并
- Spring的AOP
- MAC IOS 用openCV 绘制简单图形
- leetcode_Fizz Buzz
- windows7环境下theano的正确安装
- 防止表单重复提交的几种策略
- 风险管理(Risk Management)
- 高并发下线程安全的单例模式(最全最经典)
- 认识shell及其变量
- 错排公式推导