spring心得8--AOP各种通知案例讲解.doc

    上一篇博客中已经简单介绍了,这里通过案例详细说明一下aop中各种通知的用法。

    先列出后面介绍的JDK动态代理通知(主要区别于cglib代理而言,下面会具体介绍)、静态切入点、正则切入点等都依赖使用的抽象主题(一个接口,可以是多个)、是、真实主题(改接口的实现类)

   接口:SayService.java

package www.csdn.spring.proxy.advice;

public interface SayService {

	public void say(String content);
	public void sayHi();
	public void sayHello();
	public void byebye();
}


实现类:SayServiceImpl.java

package www.csdn.spring.proxy.advice;

public interface SayService {

	public void say(String content);
	public void sayHi();
	public void sayHello();
	public void byebye();
}
   实现类:SayServiceImpl.java
package www.csdn.spring.proxy.advice;

public class SayServiceImpl implements SayService{

	@Override
	public void say(String content) {
		System.out.println("say:"+content);
		//int i=1/0;
	}

	@Override
	public void sayHi() {
		System.out.println("===sayHi()方法执行了===");
	}

	@Override
	public void sayHello() {
		System.out.println("===sayHello()方法执行了===");
	}

	@Override
	public void byebye() {
		System.out.println("===byebye()方法执行了===");
	}

}


 

1.各种通知的使用,JDK动态代理

   前置通知、后置通知、环绕通知、异常通知、引入通知的案例分析,下面注释都有详细解释,这里不再赘述。

   spring-advice.xml  spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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.xsd">

  <!-- 创建前置通知 -->
  <bean id="beforeAdvice" class="www.csdn.spring.proxy.advice.BeforeAdvice"/>
  <!-- 创建后置通知 -->
  <bean id="afterAdvice" class="www.csdn.spring.proxy.advice.AfterAdvice"/>
  <!-- 创建环绕通知 -->
  <bean id="aroundAdvice" class="www.csdn.spring.proxy.advice.AroundAdvice"/>
  <!-- 创建异常通知 -->
  <bean id="throwAdvice" class="www.csdn.spring.proxy.advice.ThrowAdvice"/>
  <!-- 引入通知 --> 
  <bean id="auditableAdvice" class="www.csdn.spring.proxy.advice.AuditableImpl"/>
  

  <!-- 真实主题   目标对象 -->
  <bean id="sayServiceImpl" class="www.csdn.spring.proxy.advice.SayServiceImpl"/>
  
  
  <!-- 配置代理操作 -->
  <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
   
    <!--抽象主题   实现接口 -->
    <property name="proxyInterfaces">
      <array>
        <value>www.csdn.spring.proxy.advice.SayService</value>
        <value>www.csdn.spring.proxy.advice.Auditable</value>
      </array>
    </property>
    
    <!-- 目标对象 -->
    <property name="target">
      <ref bean="sayServiceImpl"/>
    </property>
    
    <!-- 织入的通知的名称 -->
    <property name="interceptorNames">
      <array>
        <value>beforeAdvice</value>
        <value>afterAdvice</value> 
        <value>aroundAdvice</value> 
        <value>throwAdvice</value> 
        <value>auditableAdvice</value> 
      </array>
    </property>
  </bean>
</beans>


 

下面是这几个通知具体反映到的类,最关键的是这个几个通知代理类所要继承的接口,不可写错,更不可不写,否则会出错,这些错误将在后期本人一篇spring错误总结的博客中涉及到,敬请期待。

   前者通知类:BeforeAdvice.java

package www.csdn.spring.proxy.advice;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class BeforeAdvice implements MethodBeforeAdvice {

	@Override
	public void before(Method method, Object[] args, Object target)
			throws Throwable {

		System.out.println("在目标方法执行之前执行........................");

		// 执行完之后执行exit方法,退出程序
		//System.exit(0);

		// 暴露的参数的含义
		System.out.println("目标方法:" + method.getName());
		if (args != null && args.length > 0) {
			for (Object arg : args) {
				System.out.println("传递的参数值:" + arg);
			}
		}
		System.out.println("目标对象:" + target.getClass());
	}

}

后置通知类:AfterAdvice.java
package www.csdn.spring.proxy.advice;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class AfterAdvice implements AfterReturningAdvice{

	@Override
	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		System.out.println("在目标方法执行之后执行..............................");
	}

}

环绕通知类:AroundAdvice.java
package www.csdn.spring.proxy.advice;

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

public class AroundAdvice implements MethodInterceptor {

	public void beforeMethod() {
		System.out.println("around---------------------目标方法之前执行");
	}

	public void afterMethod() {
		System.out.println("around---------------------目标方法之后执行");
	}

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {

		Object returnValue = null;

		beforeMethod();

		returnValue = invocation.proceed();

		afterMethod();

		return returnValue;
	}
}

异常通知类:ThrowsAdvice.java
package www.csdn.spring.proxy.advice;

import java.lang.reflect.Method;

import org.springframework.aop.ThrowsAdvice;

public class ThrowAdvice implements ThrowsAdvice{
	
	public void afterThrowing(Method m,Object[] os,Object
			target,Throwable throwable){
		System.out.println("出现异常了:"+throwable.getLocalizedMessage());
	}

}


 

引用通知需要注意是,因为这里spring使用的是jdk动态代理,所以使用引用通知的时候一定先创建一个引用通知的抽象接口,再创建一个引用通知类。

   抽象主题  Auditable.java

package www.csdn.spring.proxy.advice;

import java.util.Date;

public interface Auditable {
	
	public void setDate(Date date);
	public Date getDate();

}
  引用通知类 AuditableService.java
package www.csdn.spring.proxy.advice;

import java.util.Date;

import org.springframework.aop.support.DelegatingIntroductionInterceptor;

public class AuditableImpl extends DelegatingIntroductionInterceptor implements Auditable {

	private Date date;
	@Override
	public void setDate(Date date) {
		this.date = date;
	}

	@Override
	public Date getDate() {
		return date;
	}

}

测试类  AdviceTest.java
package www.csdn.spring.proxy.advice;

import java.util.Date;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AdviceTest {

	@Test
	public void testAdvice() {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"classpath:spring-advice.xml");

		// 不使用代理的时候
		// context.getBean("sayServiceImpl",SayServiceImpl.class).say("嗨!杨凯!");

		// 使用代理的时候
		SayService sayService = context.getBean("proxyFactoryBean", SayService.class);
		sayService.say("嗨!杨凯!");
		
		//引入通知测试
		Auditable auditable = (Auditable) sayService;
		auditable.setDate(new Date());
		System.out.println(auditable.getDate());

	}
}


 

2.各种通知的使用,cglib代理

   spring中的JDK动态代理和cglib代理区别就是:1)在配置文件中的区别,即在配置文件中抽象主键,接口对象配置不同,具体不同详见下面红色部分;主要通过property属性的proxyTargetClass值设置。2)即JDK动态代理和cglib代理的不同,前者基于接口代理,后者基于类代理,所以这里就有了真实主题的不同,即实现类的不同,cglib的真实主题没有实现任何接口。

spring-advices.xml  spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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.xsd">

  <!-- 创建前置通知 -->
  <bean id="beforeAdvice" class="www.csdn.spring.proxy.advice.BeforeAdvice"/>
  <!-- 创建后置通知 -->
  <bean id="afterAdvice" class="www.csdn.spring.proxy.advice.AfterAdvice"/>
  <!-- 创建环绕通知 -->
  <bean id="aroundAdvice" class="www.csdn.spring.proxy.advice.AroundAdvice"/>
  <!-- 创建异常通知 -->
  <bean id="throwAdvice" class="www.csdn.spring.proxy.advice.ThrowAdvice"/>
  

  <!-- 真实主题   目标对象 -->
  <bean id="sayServiceImpls" class="www.csdn.spring.proxy.advice.SayServiceImpls"/>
  
  
  <!-- 配置代理操作 -->
  <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
   
    <!--抽象主题   实现接口 -->
    <!-- 写法一:直接使用代理类,不再去指明是哪个代理类 ;这个时候value的值不管是true或false都其作用-->
    <property name="proxyTargetClass" value="true"/>      
    
    <!-- 指明代理类,这时候value必须是true的时候才起作用 ;
    使用false会报错:Bean named 'proxyFactoryBean' must be of type [www.csdn.spring.advice.SayServiceImpls], 
    but was actually of type [$Proxy4]
    <property name="proxyInterfaces">
      <array>
        <value>www.csdn.spring.proxy.advice.SayService</value>
      </array>
    </property>
    <property name="proxyTargetClass">
      <value>true</value>
    </property> 
   -->
    
    <!-- 目标对象 -->
    <property name="target">
      <ref bean="sayServiceImpls"/>
    </property>
    
    <!-- 织入的通知的名称 -->
    <property name="interceptorNames">
      <array>
        <value>beforeAdvice</value>
        <value>afterAdvice</value> 
        <value>aroundAdvice</value> 
        <value>throwAdvice</value> 
      </array>
    </property>
  </bean>
</beans>


真实主题:SayServiceImpls.java

package www.csdn.spring.proxy.advice;

public class SayServiceImpls{

	public void say(String content) {
		System.out.println("say:"+content);
	}

}
测试类  AdviceTests.java
package www.csdn.spring.proxy.advice;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AdviceTests {

	@Test
	public void testAdvice() {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"classpath:spring-advices.xml");

		// 不使用代理的时候
		// context.getBean("sayServiceImpls",SayServiceImpls.class).say("嗨!你好!");

		// 使用代理的时候
		context.getBean("proxyFactoryBean", SayServiceImpls.class).say("嗨!你好!");

	}
}


 

3.静态切入点

   为什么会有静态切入点,上一篇看博客已经介绍过,为了使你编写的通知,即代理在指定切入点起作用,也就是所谓的是aop的通知有实用价值。这里通过案例详细分析静态切入点。

spring-staticAdvisor.xml  spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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.xsd">

  <!-- 创建前置通知 -->
  <bean id="beforeAdvice" class="www.csdn.spring.proxy.advice.BeforeAdvice"/>
  <!-- 创建后置通知 -->
  <bean id="afterAdvice" class="www.csdn.spring.proxy.advice.AfterAdvice"/>
  <!-- 创建环绕通知 -->
  <bean id="aroundAdvice" class="www.csdn.spring.proxy.advice.AroundAdvice"/>
  <!-- 创建异常通知 -->
  <bean id="throwAdvice" class="www.csdn.spring.proxy.advice.ThrowAdvice"/>
  
  
  <!-- 静态切入点 -->
  <bean id="nameMatchMethodPointcutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
    <!-- 织入通知,比如环绕通知 -->
    <property name="advice">
      <ref bean="aroundAdvice"/>
    </property>
    <!-- 指明切入点 -->
    <property name="mappedName">
      <value>say</value>
    </property>
  </bean>
  

  <!-- 真实主题   目标对象 -->
  <bean id="sayServiceImpl" class="www.csdn.spring.proxy.advice.SayServiceImpl"/>
  
  
  <!-- 配置代理操作 -->
  <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
   
    <!--抽象主题   实现接口 -->
    <property name="proxyInterfaces">
      <array>
        <value>www.csdn.spring.proxy.advice.SayService</value>
      </array>
    </property>
    
    <!-- 目标对象 -->
    <property name="target">
      <ref bean="sayServiceImpl"/>
    </property>
    
    <!-- 织入的通知的名称 -->
    <property name="interceptorNames">
      <array>
        <value>nameMatchMethodPointcutAdvisor</value>
      </array>
    </property>
  </bean>
</beans>


 

测试类  AdvisorTest.java
package www.csdn.spring.proxy.advice;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AdvisorTest {

	@Test
	public void testAdvice() {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"classpath:spring-s*.xml");
		// 使用代理的时候
		SayService sayService = context.getBean("proxyFactoryBean", SayService.class);
		sayService.say("嗨!杨凯,你好!");
		sayService.sayHi();
		sayService.sayHello();
		sayService.byebye();

	}
}


 

4.正则切入点

   闲话少说,与静态切入点不同的就是正则切入点匹配正则表达式,重点代码见下面红色部分.

spring-regAdvisor.xml  spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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.xsd">

  <!-- 创建环绕通知 -->
  <bean id="aroundAdvice" class="www.csdn.spring.proxy.advice.AroundAdvice"/>
   
  
  <!-- 静态切入点 -->
  <bean id="regexpMethodPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <!-- 织入通知,比如环绕通知 -->
    <property name="advice">
      <ref bean="aroundAdvice"/>
    </property>
    <!-- 指明切入点 -->
    <property name="patterns">
    <!-- .是通配符的意思;第一个.*代表匹配任何包名和类名 ;第二个.*代表匹配以say开头的任意方法-->
      <array>
      <value>.*sayH.</value>
      <value>.*bye.*</value>
      <value>www.*\.SayService\.sayHell.</value>
      </array>
    </property>
  </bean>
  

  <!-- 真实主题   目标对象 -->
  <bean id="sayServiceImpl" class="www.csdn.spring.proxy.advice.SayServiceImpl"/>
  
  
  <!-- 配置代理操作 -->
  <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
   
    <!--抽象主题   实现接口 -->
    <property name="proxyInterfaces">
      <array>
        <value>www.csdn.spring.proxy.advice.SayService</value>
      </array>
    </property>
    
    <!-- 目标对象 -->
    <property name="target">
      <ref bean="sayServiceImpl"/>
    </property>
    
    <!-- 织入的通知的名称 -->
    <property name="interceptorNames">
      <array>
        <value>regexpMethodPointcutAdvisor</value>
      </array>
    </property>
  </bean>
</beans>


 

测试类  AdvisorTest.java

package www.csdn.spring.proxy.advice;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AdvisorTest {

	@Test
	public void testAdvice() {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"classpath:spring-r*.xml");
		// 使用代理的时候
		SayService sayService = context.getBean("proxyFactoryBean", SayService.class);
		sayService.say("嗨!杨凯,你好!");
		sayService.sayHi();
		sayService.sayHello();
		sayService.byebye();

	}
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值