javaEE——Spring 四种切面技术(拦截)获取Spring容器的两种办法
Posted wangjian_an
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javaEE——Spring 四种切面技术(拦截)获取Spring容器的两种办法相关的知识,希望对你有一定的参考价值。
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; } }
测试代码,
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); } }1.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 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配置文件演示测试代码
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(); } }AroundAdvice通知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; } }aspectj.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>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> <!-- 切面=切点+通知 (※※采用面向切点语言进行配置切面)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>
以上是关于javaEE——Spring 四种切面技术(拦截)获取Spring容器的两种办法的主要内容,如果未能解决你的问题,请参考以下文章
Spring AOP 中 advice 的四种类型 before after throwing advice around