Spring AOP编程
切面(Aspect):简单的理解就是把那些与核心业务无关的代码提取出来,进行封装成一个或几个模块用来处理那些附加的功能代码。(如日志,事务,安全验证)我们把这个模块的作用理解为一个切面,其实切面就是我们写一个类,这个类中的代码原来是在业务模块中完成的,现在单独成一个或几个类。在业务模块需要的时候才织入。
连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个连接点总是代表一个方法的执行。通过声明一个JoinPoint类型的参数可以使通知(Advice)的主体部分获得连接点信息。
切入点(Pointcut):本质上是一个捕获连接点的结构。在AOP中,可以定义一个pointcut,来捕获相关方法的调用
织入(Weaving):把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象。这些可以在编译时,类加载时和运行时完成。Spring和其它纯Java AOP框架一样,在运行时完成织入。
通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
通知的类型:
前置通知(Before advice):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
后置通知(After(finally)advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
1.RegexpMethodPointcutAdvisor切面技术
纯Java的方式实现切面(拦截)技术
下面演示代码:
public class AopDemo {
@Test//纯Java的方式实现切面(拦截)技术
public void demo1(){
Person p=new Person();
ProxyFactory factory=new ProxyFactory(); //该类的功能没有ProxyFactoryBean强
factory.setTarget(p);//1 给代理工厂一个原型对象
//切面 = 切点 + 通知
//切点
JdkRegexpMethodPointcut pointcut=new JdkRegexpMethodPointcut();
pointcut.setPattern("cn.hncu.spring4x.domain.Person.run");
// pointcut.setPattern(".*run.*");ProxyFactory对setPattern无效
Advice advice=new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("前面拦截");
Object obj=invocation.proceed();
System.out.println("后面拦截");
return obj;
}
};
//切面 = 切点 + 通知
Advisor advisor=new DefaultPointcutAdvisor(pointcut, advice);
factory.addAdvice(advice);
Person p2=(Person) factory.getProxy();
// p2.run();
// p2.run(5);
p2.say();
}
@Test//纯Java的方式实现切面(拦截)技术
public void demo2(){
ProxyFactoryBean factoryBean=new ProxyFactoryBean();
factoryBean.setTarget(new Person());
//切面 = 切点 + 通知
//切点
JdkRegexpMethodPointcut pointcut=new JdkRegexpMethodPointcut();
pointcut.setPattern(".*run.*");
//通知 前切面---不需要放行,原方法也能执行
Advice beforeAdvice=new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("beforeAdvice拦截");//正则表达式有效
}
};
Advice afterReturning=new AfterReturningAdvice() {
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("afterReturning");
}
};
Advice aroundAdvice=new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("前面拦截");
Object obj=invocation.proceed();
System.out.println("后面拦截");
return obj;
}
};
Advisor advisor1=new DefaultPointcutAdvisor(pointcut, beforeAdvice);
Advisor advisor2=new DefaultPointcutAdvisor(pointcut, afterReturning);
Advisor advisor3=new DefaultPointcutAdvisor(pointcut, aroundAdvice);
factoryBean.addAdvisors(advisor1,advisor2,advisor3);
//2 给代理工厂一个切面 ---注意,添加的顺序的拦截动作执行的顺序是有关系的!!!
//先加的切面,如果拦前面,就拦在最前面,如果拦后面,就拦在最后面.
Person p = (Person) factoryBean.getObject(); //3 从代理工厂中获取一个代理后的对象
//p.run();
//p.run(0);
p.say();
}
}
下面演示5种方式配置文件AOP
通知:AroundAdvice.java
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("前面拦拦....");
Object resObj = invocation.proceed();//放行
System.out.println("后面拦拦.....");
return resObj;
}
}
测试代码:
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AopXmlDemo {
@Test//采用配置文件的方式使用切面拦截
public void demo1(){
ApplicationContext act=new ClassPathXmlApplicationContext("cn/hncu/spring4x/aop/1.xml");
Cat cat=act.getBean("catProxide",Cat.class);//要从catProxide返回
cat.run();
cat.say();
cat.run(6);
}
@Test//把切点和通知配置成 切面的内部bean
public void demo2(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/spring4x/aop/2.xml");
Cat cat = ctx.getBean("catProxide",Cat.class);
cat.run();
cat.say();
cat.run(7);
}
@Test//直接在切面bean中配置“切点的正则表达式”,省去“切点bean”的配置
public void demo3(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/spring4x/aop/3.xml");
Cat cat = ctx.getBean("catProxide",Cat.class);
cat.run();
cat.say();
cat.run(7);
}
@Test//自动代理
public void demo4(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/spring4x/aop/4.xml");
Cat cat = ctx.getBean(Cat.class);
cat.run();
cat.say();
cat.run(7);
}
@Test//自己写的自动代理
public void demo5(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/spring4x/aop/5.xml");
Cat cat = ctx.getBean("cat",Cat.class);
// cat.run();
// cat.say();
// cat.run(7);
}
}
v1.xml:
<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<bean class="cn.hncu.spring4x.aop.Cat" id="cat"></bean>
<!-- 切点 -->
<bean class="org.springframework.aop.support.JdkRegexpMethodPointcut" id="pointcut">
<property name="pattern" value=".*run.*"></property>
</bean>
<!-- 通知 ,要自己写-->
<bean class="cn.hncu.spring4x.aop.AroundAdvice" id="advice"></bean>
<!-- 切面=切点+通知 -->
<bean class="org.springframework.aop.support.DefaultPointcutAdvisor" id="advisor">
<property name="advice" ref="advice"></property>
<property name="pointcut" ref="pointcut"></property>
</bean>
<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="catProxide">
<property name="target" ref="cat"></property>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
</bean>
</beans>
v2.xml
<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<bean class="cn.hncu.spring4x.aop.Cat" id="cat"></bean>
<!-- 切面=切点+通知 (把切点和通知写成内部bean)-->
<bean class="org.springframework.aop.support.DefaultPointcutAdvisor" id="advisor">
<property name="advice">
<bean class="cn.hncu.spring4x.aop.AroundAdvice"></bean>
</property>
<property name="pointcut">
<bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="patterns">
<list>
<value>.*run.*</value>
<value>.*say.*</value>
</list>
</property>
</bean>
</property>
</bean>
<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="catProxide">
<property name="target" ref="cat"></property>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
</bean>
</beans>
v3.xml
<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<bean class="cn.hncu.spring4x.aop.Cat" id="cat"></bean>
<!--//直接在切面bean中配置“切点的正则表达式”,省去“切点bean”的配置 用到这个类 org.springframework.aop.support.RegexpMethodPointcutAdvisor -->
<bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor">
<property name="advice">
<bean class="cn.hncu.spring4x.aop.AroundAdvice"></bean>
</property>
<property name="patterns">
<list>
<value>.*run.*</value>
</list>
</property>
</bean>
<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="catProxide">
<property name="target" ref="cat"></property>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
</bean>
</beans>
v4.xml
<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<bean class="cn.hncu.spring4x.aop.Cat" id="cat"></bean>
<!--//直接在切面bean中配置“切点的正则表达式”,省去“切点bean”的配置 用到这个类 org.springframework.aop.support.RegexpMethodPointcutAdvisor -->
<bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor">
<property name="advice">
<bean class="cn.hncu.spring4x.aop.AroundAdvice"></bean>
</property>
<property name="patterns">
<list>
<value>.*run.*</value>
</list>
</property>
</bean>
<!-- 自动代理 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
</beans>
v5.xml
<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<bean class="cn.hncu.spring4x.aop.Cat" id="cat"></bean>
<!--//直接在切面bean中配置“切点的正则表达式”,省去“切点bean”的配置 用到这个类 org.springframework.aop.support.RegexpMethodPointcutAdvisor -->
<bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor">
<property name="advice">
<bean class="cn.hncu.spring4x.aop.AroundAdvice"></bean>
</property>
<property name="patterns">
<list>
<value>.*run.*</value>
</list>
</property>
</bean>
<!-- 自动代理 -->
<bean class="cn.hncu.spring4x.aop.MyAutoProxy"></bean>
</beans>