Spring编程------aop切面技术

Posted 夏小弥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring编程------aop切面技术相关的知识,希望对你有一定的参考价值。

Spring AOP编程(1)

    面向切面编程:Aspect Oriented Programming,可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
      AOP可以说是OOP(面向对象编程)的补充和完善。在OOP设计中有可能导致代码的重复不利于模块的重用性,例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能关系不大。但是在OOP中这些业务要和核心业务代码在代码这一级集成。还有些如安全性、事务等也是如此。能不能把这些与核心业务无关但系统中需要使用的业务(称为切面)单独编写成一个模块,在主要核心业务代码中不调用,而是在配置文件中做些配置,配置核心业务需要使用到得切面部分,在系统编译时才织入到业务模块中。

Spring AOP编程(2)

    切面(Aspect):简单的理解就是把那些与核心业务无关的代码提取出来,进行封装成一个或几个模块用来处理那些附加的功能代码。(如日志,事务,安全验证)我们把这个模块的作用理解为一个切面,其实切面就是我们写一个类,这个类中的代码原来是在业务模块中完成的,现在单独成一个或几个类。在业务模块需要的时候才织入。
    连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个连接点总是代表一个方法的执行。通过声明一个JoinPoint类型的参数可以使通知(Advice)的主体部分获得连接点信息。  
    切入点(Pointcut):本质上是一个捕获连接点的结构。在AOP中,可以定义一个pointcut,来捕获相关方法的调用

Spring AOP编程(3)

      织入(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)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。

Spring AOP编程(5)

 

第1步: 编写一个类封装用户的常见操作。 UserDao.java
package com.aop;
public class UserDao 
   public void save(String name)
	     System.out.println("----save user----");
   
   public void delete()
	      System.out.println("----delete user----");
   
   public void update()
	  System.out.println("----update user----");
   
 

第2步: 编写一个检查用户是否合法的类。

package com.aop;
public class CheckSecurity 
    public void check() System.out.println("--check admin--");
    

第3步: 改写Spring的配置文件

<bean id="checkbean" class="com.aop.CheckSecurity"></bean>
<bean id="userDao" class="com.aop.UserDao"/>
 <aop:config>
    <aop:aspect id="security" ref="checkbean">
       <aop:pointcut id="allAddMethod" expression=
                     "execution(* com.aop.UserDao.*(..))"/>
       <aop:before method="check" pointcut-ref= "allAddMethod"/>
    </aop:aspect>
</aop:config>

第4步:编写测试类 Test.java。

 

 

package com.aop;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.*;
public class Test 
     public static void main(String[] args) 
		 /* 读取Spring配置文件,创建一个Bean工厂 */
       BeanFactory factory = new 
      ClassPathXmlApplicationContext(“applicationContext.xml”);  
       UserDao dao = (UserDao) factory.getBean("userDao");
       dao.save("zhou");
	  




下面出示我写的两个例子

 

例一:

Person.java

 

package cn.hncu.spring4.aop.demo3;

public class Person 
	public void run()
		System.out.println("I'm running...");
	
	public void run(int i)
		System.out.println("I'm running..."+i);
	
	public void speak()
		System.out.println("I'm speaking...");
	

AopDemo.java

 

 

package cn.hncu.spring4.aop.demo3;

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;

public class AopDemo 
	@Test //纯Java的方式实现切面(拦截)技术
	public void demo1()
		Person p=new Person();//被代理的原型对象
		ProxyFactory factory=new ProxyFactory();//该类的功能没有ProxyFactoryBean强
		factory.setTarget(p);//1、给代理工厂一个原型对象
		
		//切面 = 切点 + 通知
		//切点
		JdkRegexpMethodPointcut cut=new JdkRegexpMethodPointcut();
//		cut.setPattern("cn.hncu.spring4.aop.demo3.Person.run");
		cut.setPattern(".*run.*");//参数是正则表达式
		
		//通知
		Advice advice=new MethodInterceptor() 
			
			@Override
			public Object invoke(MethodInvocation methodInv) throws Throwable 
				System.out.println("前面拦");
				Object resObj=methodInv.proceed();
				System.out.println("后面拦");
				return resObj;
			
		;
		
		//切面 = 切点 + 通知
		Advisor advisor=new DefaultPointcutAdvisor(cut, advice);
		factory.addAdvisor(advisor);//2 给代理工厂一个切面
		Person p2=(Person) factory.getProxy();
		p2.run();
		p2.run(6);
		p2.speak();//不会拦
	
	
	@Test
	public void demo2()
		Person p=new Person();//被代理的原型对象
		ProxyFactoryBean factory=new ProxyFactoryBean();
		factory.setTarget(p);//1、给代理工厂一个原型对象
		
		//切面 = 切点 + 通知
		//切点
		JdkRegexpMethodPointcut cut=new JdkRegexpMethodPointcut();
//		cut.setPattern("cn.hncu.spring4.aop.demo3.Person.run");
		cut.setPatterns(".*run.*",".*speak.*");//参数是正则表达式
		
		//通知  前切面---不需要放行,原方法也能执行
		Advice before=new MethodBeforeAdvice() 
			
			@Override
			public void before(Method arg0, Object[] arg1, Object arg2)
					throws Throwable 
				System.out.println("前置通知...before");
			
		;
		
		//返回后通知
		Advice afterReturning=new AfterReturningAdvice() 
			
			@Override
			public void afterReturning(Object arg0, Method arg1, Object[] arg2,
					Object arg3) throws Throwable 
				System.out.println("返回后通知...afterReturning");
			
		;
		
		Advice around=new MethodInterceptor() 
			
			@Override
			public Object invoke(MethodInvocation arg0) throws Throwable 
				System.out.println("在前面拦");
				Object returnValue=arg0.proceed();
				System.out.println("在后面拦");
				return returnValue;
			
		;
		
		//切面 = 切点 + 通知
		Advisor advisor1=new DefaultPointcutAdvisor(before);
		Advisor advisor2=new DefaultPointcutAdvisor(afterReturning);
		Advisor advisor3=new DefaultPointcutAdvisor(around);
		
		factory.addAdvisors(advisor3,advisor2,advisor1);//2 给代理工厂一个切面 ---注意,添加的顺序的拦截动作执行的顺序是有关系的!!!
		//其实也就只有一种情况要注意,就是环绕的around这种放在最前面添加这种,会把其他的通知都包括进去,
		//即,环绕的这种的前面拦截的会在最前面,后面拦截的会在最后面
		Person p2=(Person) factory.getObject();//3 从代理工厂中获取一个代理后的对象
		p2.run();
		p2.speak();
	


例二(此例要更加深入一些):
Person.java

 

 

package cn.hncu.spring4.aop.demo4;

public class Person 
	public void run()
		System.out.println("I'm running...");
	
	public void run(int i)
		System.out.println("I'm running..."+i);
	
	public void speak()
		System.out.println("I'm speaking...");
	

AopXmlDemo.java  此类中用到了四个配置文件,在下面我都会贴出来,每一个都不一样

 

 

package cn.hncu.spring4.aop.demo4;

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/spring4/aop/demo4/1.xml");
		Person p=act.getBean("personProxied", Person.class);
		p.run();
	
	
	@Test//把切点和通知配置成 切面的内部bean
	public void demo2()
		ApplicationContext act=new ClassPathXmlApplicationContext("cn/hncu/spring4/aop/demo4/2.xml");
		Person p=act.getBean("personProxied", Person.class);
		p.run();
	
	
	@Test//直接在切面bean中配置“切点的正则表达式”,省去“切点bean”的配置
	public void demo3()
		ApplicationContext act=new ClassPathXmlApplicationContext("cn/hncu/spring4/aop/demo4/3.xml");
		Person p=act.getBean("personProxied", Person.class);
		p.run();
	
	
	@Test
	public void demo4()
		ApplicationContext act=new ClassPathXmlApplicationContext("cn/hncu/spring4/aop/demo4/4.xml");
		Person p=act.getBean(Person.class);
		p.run();
	

AroundAdvice.java

 

 

package cn.hncu.spring4.aop.demo4;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class AroundAdvice implements MethodInterceptor 

	@Override
	public Object invoke(MethodInvocation methodInv) throws Throwable 
		System.out.println("前面拦");
		Object resObj=methodInv.proceed();
		System.out.println("后面拦");
		return resObj;
	

配置文件

 

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="p" class="cn.hncu.spring4.aop.demo4.Person"></bean>
	
	<!-- 切点 -->
	<bean id="cut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
		<property name="pattern" value=".*run.*"></property>
	</bean>
	<!-- 通知 -->
	<bean id="advice" class="cn.hncu.spring4.aop.demo4.AroundAdvice"></bean>
	<!-- 切面=切点+通知 -->
	<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		<property name="pointcut" ref="cut"></property>
		<property name="advice" ref="advice"></property>
	</bean>
	
	<bean id="personProxied" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="p"></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="p" class="cn.hncu.spring4.aop.demo4.Person"></bean>
	
	<!-- 切面=切点+通知 (把切点和通知写成内部bean)-->
	<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		<property name="pointcut">
			<bean id="cut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
				<property name="pattern" value=".*run.*"></property>
			</bean>
		</property>
		<property name="advice">
			<bean id="advice" class="cn.hncu.spring4.aop.demo4.AroundAdvice"></bean>
		</property>
	</bean>
	
	<bean id="personProxied" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="p"></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="p" class="cn.hncu.spring4.aop.demo4.Person"></bean>
	
	<!-- 切面=切点+通知 (把切点和通知写成内部bean),直接在切面bean中配置“切点的正则表达式”,省去“切点bean”的配置-->
	<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
		<property name="patterns">
			<list>
				<value>.*run.*</value>
			</list>
		</property>
		
		<property name="advice">
			<bean id="advice" class="cn.hncu.spring4.aop.demo4.AroundAdvice"></bean>
		</property>
	</bean>
	
	<bean id="personProxied" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="p"></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="p" class="cn.hncu.spring4.aop.demo4.Person"></bean>
	
	<!-- 切面=切点+通知 (把切点和通知写成内部bean),直接在切面bean中配置“切点的正则表达式”,省去“切点bean”的配置-->
	<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
		<property name="patterns">
			<list>
				<value>.*run.*</value>
			</list>
		</property>
		
		<property name="advice">
			<bean id="advice" class="cn.hncu.spring4.aop.demo4.AroundAdvice"></bean>
		</property>
	</bean>
	
	<!--自动代理 
	  <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
	 -->
	<bean class="cn.hncu.spring4.aop.demo4.MyAutoProxy"></bean>
</beans>

MyAotuProxy.java 这是自己写的一个自动代理(在用ApplicationContext新建对象的时候自动为它代理),这个是配合4.xml用的,因此就和4.xml放一起了



 

 

以上是关于Spring编程------aop切面技术的主要内容,如果未能解决你的问题,请参考以下文章

Spring-AOP(面向切面编程)

Spring编程------aop切面技术

Spring编程------aop切面技术

Spring框架第五篇之Spring与AOP

Spring AOP面向切面编程

Spring:AOP, 面向切面编程