首页 > 代码库 > javaEE——Spring 四种切面技术(拦截)、获取Spring容器的两种办法

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:在方法抛出异常退出时执行的通知。
    后置通知(Afterfinallyadvice:当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

     环绕通知(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=http://www.mamicode.com/".*run.*">>
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=http://www.mamicode.com/"execution( * cn.hncu..*son.*(*,..) )">>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=http://www.mamicode.com/"execution( * cn.hncu..*son.*(*,..) )">>







javaEE——Spring 四种切面技术(拦截)、获取Spring容器的两种办法