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方式写AOP(拦截技术)
- package cn.hncu.spring4x.aop;
- import java.lang.reflect.Method;
- import org.aopalliance.aop.Advice;
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- import org.junit.Test;
- import org.springframework.aop.Advisor;
- import org.springframework.aop.AfterReturningAdvice;
- import org.springframework.aop.MethodBeforeAdvice;
- import org.springframework.aop.framework.ProxyFactory;
- import org.springframework.aop.framework.ProxyFactoryBean;
- import org.springframework.aop.support.DefaultPointcutAdvisor;
- import org.springframework.aop.support.JdkRegexpMethodPointcut;
- import cn.hncu.spring4x.domain.Person;
- 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
- package cn.hncu.spring4x.aop;
- 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;
- }
- }
测试代码,
1.xml
- package cn.hncu.spring4x.aop;
- 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);
- }
- }
- <?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:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx"
- 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 id="cat" class="cn.hncu.spring4x.aop.Cat"></bean>
- <!-- 切点 -->
- <bean id="pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
- <property name="pattern" value=".*run.*"></property>
- </bean>
- <!-- 通知 ,要自己写-->
- <bean id="advice" class="cn.hncu.spring4x.aop.AroundAdvice"></bean>
- <!-- 切面=切点+通知 -->
- <bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
- <property name="advice" ref="advice"></property>
- <property name="pointcut" ref="pointcut"></property>
- </bean>
- <bean id="catProxide" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target" ref="cat"></property>
- <property name="interceptorNames">
- <list>
- <value>advisor</value>
- </list>
- </property>
- </bean>
- </beans>
2.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:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx"
- 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 id="cat" class="cn.hncu.spring4x.aop.Cat"></bean>
- <!-- 切面=切点+通知 (把切点和通知写成内部bean)-->
- <bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
- <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 id="catProxide" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target" ref="cat"></property>
- <property name="interceptorNames">
- <list>
- <value>advisor</value>
- </list>
- </property>
- </bean>
- </beans>
3.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:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx"
- 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 id="cat" class="cn.hncu.spring4x.aop.Cat"></bean>
- <!--//直接在切面bean中配置“切点的正则表达式”,省去“切点bean”的配置 用到这个类 org.springframework.aop.support.RegexpMethodPointcutAdvisor -->
- <bean id="advisor"
- class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
- <property name="advice">
- <bean class="cn.hncu.spring4x.aop.AroundAdvice"></bean>
- </property>
- <property name="patterns">
- <list>
- <value>.*run.*</value>
- </list>
- </property>
- </bean>
- <bean id="catProxide" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target" ref="cat"></property>
- <property name="interceptorNames">
- <list>
- <value>advisor</value>
- </list>
- </property>
- </bean>
- </beans>
4.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:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx"
- 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 id="cat" class="cn.hncu.spring4x.aop.Cat"></bean>
- <!--//直接在切面bean中配置“切点的正则表达式”,省去“切点bean”的配置 用到这个类 org.springframework.aop.support.RegexpMethodPointcutAdvisor -->
- <bean id="advisor"
- class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
- <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>
5.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:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx"
- 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 id="cat" class="cn.hncu.spring4x.aop.Cat"></bean>
- <!--//直接在切面bean中配置“切点的正则表达式”,省去“切点bean”的配置 用到这个类 org.springframework.aop.support.RegexpMethodPointcutAdvisor -->
- <bean id="advisor"
- class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
- <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>
第五种方法,模拟自动代理MyAutoProxy.java
- package cn.hncu.spring4x.aop;
- import org.springframework.aop.Advisor;
- import org.springframework.aop.framework.ProxyFactoryBean;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.factory.config.BeanPostProcessor;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- public class MyAutoProxy implements BeanPostProcessor,ApplicationContextAware{
- private ApplicationContext applicationContext;
- @Override
- public void setApplicationContext(ApplicationContext applicationContext)
- throws BeansException {
- this.applicationContext=applicationContext;//保证是同一个容器
- }
- @Override
- public Object postProcessBeforeInitialization(Object bean, String beanName)
- throws BeansException {
- System.out.println(bean+"postProcessBeforeInitialization");
- return bean; //直接放行(一定要)
- }
- @Override
- public Object postProcessAfterInitialization(Object bean, String beanName)
- throws BeansException {
- System.out.println(bean+"postProcessAfterInitialization");
- ProxyFactoryBean factoryBean=new ProxyFactoryBean();
- factoryBean.setTarget(bean);
- Advisor advisor=applicationContext.getBean("advisor", Advisor.class);
- factoryBean.addAdvisor(advisor);
- return factoryBean.getObject();
- }
- }
2.AspectJExpressionPointcut切面技术
纯java代码演示:
Person.java
- package cn.hncu.spring4x.aspectj;
- public class Person {
- public void run(){
- System.out.println("run............");
- }
- public void run(int i){
- System.out.println(i+"run............");
- }
- public int run(String str,int i){
- System.out.println(str+"run............"+i);
- return 0;
- }
- public void run(String str){
- System.out.println(str+"run............");
- }
- public void say() {
- System.out.println("say............");
- }
- public Person say(String str) {
- System.out.println("say..........str.");
- return null;
- }
- }
- package cn.hncu.spring4x.aspectj;
- import org.aopalliance.aop.Advice;
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- import org.junit.Test;
- import org.springframework.aop.Advisor;
- import org.springframework.aop.aspectj.AspectJExpressionPointcut;
- import org.springframework.aop.framework.ProxyFactoryBean;
- import org.springframework.aop.support.DefaultPointcutAdvisor;
- public class AspectjDemo {
- @Test//纯java方式
- public void demo1(){
- ProxyFactoryBean factoryBean=new ProxyFactoryBean();
- factoryBean.setTarget(new Person());
- //声明一个aspectj切点
- AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
- //参数用切点语言来写
- // pointcut.setExpression("execution( void cn.hncu.spring4x.aspectj.Person.run() )");//拦: 空参空返回值的run方法
- // pointcut.setExpression("execution( void cn.hncu.spring4x.aspectj.Person.*() )");//拦: 空参空返回值的任意方法
- // pointcut.setExpression("execution( void cn.hncu.spring4x.aspectj.Person.*(String) )"); //拦: 只有1个String类型参数,空返回值的任意方法
- // pointcut.setExpression("execution( void cn.hncu.spring4x.aspectj.Person.*(*) )"); //拦: 有1个参数(类型不限),空返回值的任意方法
- // pointcut.setExpression("execution( void cn.hncu.spring4x.aspectj.Person.*(..) )"); //拦: 任意(个数和类型)参数,空返回值的任意方法
- // pointcut.setExpression("execution( void cn.hncu.spring4x.aspectj.Person.*(*,..) )"); //拦: 至少有1个参数(类型不限),空返回值的任意方法
- // pointcut.setExpression("execution( * cn.hncu.spring4x.aspectj.Person.*(*,*) )"); //拦: 有2个参数(类型不限),任意返回值的任意方法
- pointcut.setExpression("execution( cn.hncu.spring4x.aspectj.Person cn.hncu.spring4x.aspectj.Person.*(*,..) )"); //拦: 至少有1个参数(类型不限),返回值类型是Person的任意方法——不是基础数据类型要用全名
- pointcut.setExpression("execution( * cn.hncu..**son.*(..) )"); //拦: cn.hncu包下,类名以"son"结束, 函数、返回类型和参数任意
- 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);
- factoryBean.addAdvisor(advisor);
- Person p=(Person) factoryBean.getObject();
- p.run();
- p.run(5);
- p.run("有返回值有int0",5);
- p.run("没有返回值");
- p.say();
- }
- }
xml配置文件演示
测试代码
AroundAdvice通知
- package cn.hncu.spring4x.aspectj;
- import org.junit.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class AspectjXmlDemo {
- @Test
- public void demo(){
- ApplicationContext act=new ClassPathXmlApplicationContext("cn/hncu/spring4x/aspectj/aspectj.xml");
- Person p=act.getBean("person", Person.class);
- p.run();
- p.run(5);
- p.run("有返回值有int0",5);
- p.run("没有返回值");
- p.say();
- }
- @Test
- public void demo2(){
- ApplicationContext act=new ClassPathXmlApplicationContext("cn/hncu/spring4x/aspectj/aspectj2.xml");
- Person p=act.getBean("person", Person.class);
- p.run();
- p.run(5);
- p.run("有返回值有int0",5);
- p.run("没有返回值");
- p.say();
- }
- }
aspectj.xml
- package cn.hncu.spring4x.aspectj;
- 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;
- }
- }
aspectj2.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:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx"
- 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 id="person" class="cn.hncu.spring4x.aspectj.Person"></bean>
- <bean id="advice" class="cn.hncu.spring4x.aspectj.AroundAdvice"></bean>
- <bean id="pointcut" class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
- <property name="expression" value="execution( * cn.hncu..*son.*(*,..) )"></property>
- </bean>
- <!-- 切面=切点+通知 (※※采用面向切点语言进行配置切面)-->
- <bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
- <property name="advice" ref="advice"></property>
- <property name="pointcut" ref="pointcut"></property>
- </bean>
- <!-- 自动代理 -->
- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
- </beans>
- <?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:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx"
- 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 id="person" class="cn.hncu.spring4x.aspectj.Person"></bean>
- <!-- 切面=切点+通知 (※※采用面向切点语言进行配置切面)org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor -->
- <bean id="advisor"
- class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
- <property name="expression" value="execution( * cn.hncu..*son.*(*,..) )"></property>
- <property name="advice">
- <bean id="advice" class="cn.hncu.spring4x.aspectj.AroundAdvice"></bean>
- </property>
- </bean>
- <!-- 自动代理 -->
- <bean
- class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
- </beans>
实战:通过aspectj对c3po中多的的connection对象的close()方法进行拦截,保证同一用户拿到同一线程,以及实现事务
这是applicationContext.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:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx"
- 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">
- <context:property-placeholder location="WEB-INF/conf/jdbc.properties"/>
- <bean id="dataSourse" class="org.springframework.jdbc.datasource.SimpleDriverDataSource" >
- <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
- <property name="url" value="${url}"></property>
- <property name="username" value="${name}"></property>
- <property name="password" value="${pwd}"></property>
- <!-- 不能用${username}和${password} -->
- </bean>
- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
- <bean id="tx"
- class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
- <property name="expression" value="execution( * cn.hncu..*Service.*(..) )"></property>
- <!-- 要拦Service不能拦ServiceImpl依赖抽象 -->
- <property name="advice">
- <bean class="cn.hncu.utils.TxAdvice"></bean>
- </property>
- </bean>
- <bean id="closeCon" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
- <property name="expression" value="execution( * *..*.*.getConnection() )"></property>
- <property name="advice">
- <bean class="cn.hncu.utils.CloseAdvice"></bean>
- </property>
- </bean>
- </beans>
TxAdvice.java
- package cn.hncu.utils;
- import java.sql.Connection;
- import javax.sql.DataSource;
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- import org.springframework.beans.BeansException;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- public class TxAdvice implements MethodInterceptor,ApplicationContextAware{
- private ApplicationContext act;
- @Override
- public void setApplicationContext(ApplicationContext act)
- throws BeansException {
- this.act=act;
- }
- @Override
- public Object invoke(MethodInvocation invocation) throws Throwable {
- DataSource ds=act.getBean("dataSourse", DataSource.class);
- Connection con=ds.getConnection();
- con.setAutoCommit(false);
- System.out.println("开启一个事务");
- Object obj = null;
- try {
- obj = invocation.proceed();
- System.out.println("提交一个事务");
- con.commit();
- } catch (Exception e) {
- System.out.println("回滚一个事务");
- con.rollback();
- }finally{
- try {
- con.setAutoCommit(true);
- con.close();
- } catch (Exception e2) {
- }
- }
- return obj;
- }
- }
CloseAdive.java
在这里测试出c3p0每次增删改都会调用一次close方法
- package cn.hncu.utils;
- import java.lang.reflect.Method;
- import java.sql.Connection;
- import net.sf.cglib.proxy.Callback;
- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodProxy;
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- public class CloseAdvice implements MethodInterceptor{//代理getConnetion
- private ThreadLocal<Connection> tl=new ThreadLocal<Connection>();
- @Override
- public Object invoke(MethodInvocation invocation) throws Throwable {
- Connection con=tl.get();
- if(con!=null){
- System.out.println(con.hashCode()+":::::"+invocation.getMethod().getName());
- }
- if(con==null){
- final Connection con2=(Connection) invocation.proceed();
- Callback callback = new net.sf.cglib.proxy.MethodInterceptor(){
- @Override
- public Object intercept(Object proxiedObj, Method method,
- Object[] args, MethodProxy proxy) throws Throwable {
- if(method.getName().equalsIgnoreCase("close")){
- System.out.println("close代理"+proxiedObj);
- return null;
- }
- return method.invoke(con2, args);
- }
- };
- con=(Connection) Enhancer.create(Connection.class, callback);
- tl.set(con);
- }
- return con;
- }
- }
3.注解(POJO)-----aop自动代理 xmlns:aop="http://www.springframework.org/schema/aop"
注意:要在对于不同的jdk版本要加入不同的织入包,因为我的是jdk1.7所有我加入的包是1.7版本的
通过注解来对进行切面
anno.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:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
- 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
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd ">
- <!-- 使用aop标签配自动代理 -->
- <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- <bean id="p" class="cn.hncu.spring4x.annoAop.Person"></bean>
- <!--基于注解的切面(切面=切点+通知),该类通过@Aspect注解让自动代理知道它是一个切面 -->
- <!-- 切点寄宿在方法上 -->
- <!-- <bean class="cn.hncu.spring4x.annoAop.MyAdivor"></bean> -->
- <!-- 切点寄宿在属性上 -->
- <bean class="cn.hncu.spring4x.annoAop.MyAdivor2"></bean>
- </beans>
Myadvisor.java
- package cn.hncu.spring4x.annoAop;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.After;
- import org.aspectj.lang.annotation.AfterReturning;
- import org.aspectj.lang.annotation.AfterThrowing;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.aspectj.lang.annotation.Pointcut;
- @Aspect //1 把当前类标记为一个切面--否则自动代理不知道该类是一个切面
- public class MyAdivor {
- //2 切点 ---通过方法名标识该切点
- @Pointcut(value="execution( * cn.hncu..*son.*(*,..) )")
- public void pointcut(){
- }
- @Before(value="pointcut()")//3 指定通知类型为before,切点为px()方法上的那个@Pointcut注解
- public void before(){
- System.out.println("在拦截之前");
- }
- @After(value="pointcut()")
- public void after(){
- System.out.println("在拦截之后");
- }
- @Around(value="pointcut()")//Spring不建议使用周围通知,因为要依赖于ProceedingJoinPoint类---建议联合使用“@Before”和“@After”来实现周围通知的功能
- public Object around(ProceedingJoinPoint pjp) throws Throwable{
- System.out.println("前");
- Object res = pjp.proceed();
- System.out.println("后");
- return res;
- }
- @AfterReturning(value="pointcut()")//理解“正常返回”: 该通知在方法出现异常又没有捕捉时,是不会执行(没有出现异常)
- public void afternReturning(){
- System.out.println("没有出现异常");
- }
- @AfterThrowing(value="pointcut()")//如果被拦截方法出现没捕捉的异常,则该方法会执行。反之,不会执行...(有异常)
- public void afternThrowing(){
- System.out.println("被拦截方法出现没捕捉的异常");
- }
- }
Myadvisor.java
- package cn.hncu.spring4x.annoAop;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.After;
- import org.aspectj.lang.annotation.AfterReturning;
- import org.aspectj.lang.annotation.AfterThrowing;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.aspectj.lang.annotation.Pointcut;
- @Aspect //1 把当前类标记为一个切面--否则自动代理不知道该类是一个切面
- public class MyAdivor2 {
- //2 切点(基于属性的切点) ---通过属性名标识该切点
- private final String CUT="execution( * cn.hncu..*son.*(*,..))";
- //2 切点 ---通过方法名标识该切点
- @Pointcut(value=CUT)
- public void pointcut(){
- }
- @Before(value=CUT)//3 指定通知类型为before,切点为px()方法上的那个@Pointcut注解
- public void before(){
- System.out.println("在拦截之前");
- }
- @After(value=CUT)
- public void after(){
- System.out.println("在拦截之后");
- }
- @Around(value=CUT)//Spring不建议使用周围通知,因为要依赖于ProceedingJoinPoint类---建议联合使用“@Before”和“@After”来实现周围通知的功能
- public Object around(ProceedingJoinPoint pjp) throws Throwable{
- System.out.println("前");
- Object res = pjp.proceed();
- System.out.println("后");
- return res;
- }
- @AfterReturning(value=CUT)//理解“正常返回”: 该通知在方法出现异常又没有捕捉时,是不会执行(没有出现异常)
- public void afternReturning(){
- System.out.println("没有出现异常");
- }
- @AfterThrowing(value=CUT)//如果被拦截方法出现没捕捉的异常,则该方法会执行。反之,不会执行...(有异常)
- public void afternThrowing(){
- System.out.println("被拦截方法出现没捕捉的异常");
- }
- }
在Web项目中使用注解处理事务:(JdbcDaoSupport,org.springframework.jdbc.datasource.DataSourceTransactionManager,@Transactional)
applicationContext.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:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
- 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
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd ">
- <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
- <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
- <property name="url" value="jdbc:mysql:///sstud?characterEncoding=UTF-8"></property>
- <property name="username" value="root"></property>
- <property name="password" value="1234"></property>
- </bean>
- <bean id="closeCon"
- class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
- <property name="expression" value="execution( * *..*.*.getConnection() )"></property>
- <property name="advice">
- <bean class="cn.hncu.utils.CloseAdvice"></bean>
- </property>
- </bean>
- <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"></property>
- </bean>
- <tx:annotation-driven proxy-target-class="true" transaction-manager="txManager"/>
- </beans>
StudDaoJdbc.java
- package cn.hncu.stud.dao;
- import java.sql.SQLException;
- import java.util.UUID;
- import javax.sql.DataSource;
- import org.apache.commons.dbutils.QueryRunner;
- import org.springframework.jdbc.core.support.JdbcDaoSupport;
- import cn.hncu.stud.domain.Book;
- import cn.hncu.stud.domain.Stud;
- public class StudDaoImpl extends JdbcDaoSupport implements StudDao {
- @Override
- public void saveStud(Stud stud) throws SQLException {
- stud.setId(UUID.randomUUID().toString().replaceAll("-", "").substring(0,5));
- getJdbcTemplate().update("insert stud(id,name) value(?,?)",stud.getId(),stud.getName());
- }
- @Override
- public void saveBook(Book book) throws SQLException {
- getJdbcTemplate().update("insert book(name) value(?)",book.getName());
- }
- }
StudServiceImpl.java
- package cn.hncu.stud.service;
- import java.sql.SQLException;
- import javax.ejb.TransactionManagement;
- import org.springframework.transaction.annotation.Propagation;
- import org.springframework.transaction.annotation.Transactional;
- import cn.hncu.stud.dao.StudDao;
- import cn.hncu.stud.domain.Book;
- import cn.hncu.stud.domain.Stud;
- public class StudServiceImpl implements IStudService{
- private StudDao dao=null;
- @Override
- @Transactional(propagation=Propagation.REQUIRES_NEW)
- public void save(Stud stud, Book book) throws SQLException {
- dao.saveStud(stud);
- dao.saveBook(book);
- }
- public StudDao getDao() {
- return dao;
- }
- public void setDao(StudDao dao) {
- this.dao = dao;
- }
- }
4.纯POJO切面技术(使用<aop:config>来进行配置)
pojo.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:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
- 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
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd ">
- <!-- 使用aop标签配自动代理 -->
- <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- <bean id="p" class="cn.hncu.spring4x.annoAop.Person"></bean>
- <!-- 基于POJO的切面 -->
- <bean id="pojo" class="cn.hncu.spring4x.pojoAop.MyAdivsor"></bean>
- <aop:config>
- <aop:pointcut expression="execution( * cn.hncu..*son.*(*,..) )" id="pointcut"/>
- <aop:aspect ref="pojo">
- <aop:after method="after" pointcut-ref="pointcut"/>
- <aop:before method="before" pointcut-ref="pointcut"/>
- </aop:aspect>
- </aop:config>
- </beans>
MyAdvisor,java
- package cn.hncu.spring4x.pojoAop;
- public class MyAdivsor {
- public void before(){
- System.out.println("之前拦拦.....");
- }
- public void after(){
- System.out.println("之后拦拦666....");
- }
- }
获得获取Spring容器的两种办法(ApplicationContext)
1.在Servlet中通过WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());去拿
- @Override//※※※※※获取Web中的spring容器---法1
- public void init() throws ServletException {
- ApplicationContext act=WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
- service=act.getBean("studService",IStudService.class);
- }
2.通过实现ApplicationContextAware去拿
- <span style="font-size:14px;">public class TxAdvice implements ApplicationContextAware{
- private ApplicationContext act;
- @Override
- public void setApplicationContext(ApplicationContext act)
- throws BeansException {
- this.act=act;
- }
- }</span>