`

Spring AOP四种创建通知(拦截器)类型实例

 
阅读更多

1、Spring只支持方法拦截,也就是说,只能在方法的前后进行拦截,而不能在属性前后进行拦截。
2、Spring支持四种拦截类型:目标方法调用前(before),目标方法调用后(after),目标方法调用前后(around),以及目标方法抛出异常(throw)。
3、前置拦截的类必须实现MethodBeforeAdvice接口,实现其中的before方法。
4、后置拦截的类必须实现AfterReturningAdvice接口,实现其中的afterReturning方法。
5、前后拦截的类必须实现MethodInterceptor接口,实现其中的invoke方法。前后拦截是唯一可以控制目标方法是否被真正调用的拦截类型,也可以控制返回对象。而前置拦截或后置拦截不能控制,它们不能印象目标方法的调用和返回。
但是以上的拦截的问题在于,不能对于特定方法进行拦截,而只能对某个类的全部方法作拦截。所以下面引入了两个新概念:“切入点”和“引入通知”。
6、”切入点“的定义相当于更加细化地规定了哪些方法被哪些拦截器所拦截,而并非所有的方法都被所有的拦截器所拦截。在ProxyFactoryBean的属性中,interceptorNames属性的对象也由拦截(Advice)变成了引入通知(Advisor),正是在Advisor中详细定义了切入点(PointCut)和拦截(Advice)的对应关系,比如常见的基于名字的切入点匹配(NameMatchMethodPointcutAdvisor类)和基于正则表达式的切入点匹配(RegExpPointcutAdvisor类)。这些切入点都属于”静态切入点“,因为他们只在代理创建的时候被创建一次,而不是每次运行都创建。

下面我们进行实例的开发

首先创建业务接口: 

package AdvisorTest;

public interface Shopping ...{
  
public String buySomething(String type);
  
public String buyAnything(String type);
  
public void testException();
}

 下面是业务实现类,我们的通知就是以这些实现类作为切面,在业务方法前后加入我们的通知代码 

package AdvisorTest;

public class ShoppingImpl implements Shopping ...{
    
private Customer customer;
    
public Customer getCustomer() ...{
        
return customer;
    }

    
public void setCustomer(Customer customer) ...{
        
this.customer = customer;
    }

    
public String buySomething(String type) ...{
        System.out.println(
this.getCustomer().getName()+" bye "+type+" success");
        
return null;
    }

    
    
public String buyAnything(String type) ...{
       System.out.println(
this.getCustomer().getName()+" bye "+type+" success");
       
return null;

     }

    
public void testException()...{
        
throw new ClassCastException();
    }

}

 (1)前置通知

        配置了前置通知的bean,在执行业务方法前,均会执行前置拦截器的before方法

package AdvisorTest;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;
//前置通知
public class WelcomeAdvice implements MethodBeforeAdvice ...{

    
public void before(Method method, Object[] args, Object obj)
            
throws Throwable ...{
        String type
=(String)args[0];
        System.out.println(
"Hello welcome to bye "+type);

    }


}

 (2)后置通知

配置了前置通知的bean,在执行业务方法前,均会执行前置拦截器的afterReturnning方法

package AdvisorTest;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
//后置通知
public class ThankYouAdvice implements AfterReturningAdvice ...{

    
public void afterReturning(Object obj, Method method, Object[] arg1,
            Object arg2) 
throws Throwable ...{
        
         String type
=(String)arg1[0];
         System.out.println(
"Hello Thankyou to bye "+type);
    }

    

}

 (3)环绕通知

配置了前置通知的bean,在执行业务方法前后,均会执行前置拦截器的invoke方法

需要注意的是必须调用目标方法,如不调用,目标方法将不被执行

package AdvisorTest;

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

public class MethodAdvisor implements MethodInterceptor ...{

    
public Object invoke(MethodInvocation invocation) throws Throwable ...{
        String str
=(String)invocation.getArguments()[0];
        System.out.println(
"this is before"+str+" in MethodInterceptor");
        Object obj
=invocation.proceed(); //调用目标方法,如不调用,目标方法将不被执行
        System.out.println("this is after"+str+" in MethodInterceptor");
        
return null;
    }


}

 (4)异常通知

ThrowsAdvice是一个标示接口,我们可以在类中定义一个或多个,来捕获定义异常通知的bean抛出的异常,并在抛出异常前执行相应的方法

public void afterThrowing(Throwable throwa){}或者

public void afterThrowing(Method method,Object[] args,Object target,Throwable throwable){

package AdvisorTest;

import org.springframework.aop.ThrowsAdvice;

public  class ExceptionAdvisor implements ThrowsAdvice ...{
  
public void afterThrowing(ClassCastException e)...{
      System.out.println(
"this is from exceptionAdvisor");
  }

}

 配置文件 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
<beans>
 
<bean id="customer" class="AdvisorTest.Customer">
   
<constructor-arg index="0">
     
<value>gaoxiang</value>
   
</constructor-arg>
    
<constructor-arg index="1">
     
<value>26</value>
   
</constructor-arg>
 
</bean>
 
 
<bean id="shoppingImpl" class="AdvisorTest.ShoppingImpl">
   
<property name="customer">
     
<ref local="customer"/>
   
</property>
 
</bean>

<!-- 前置通知 -->
<bean id="welcomeAdvice" class="AdvisorTest.WelcomeAdvice"/>
<bean id="welcomeAdviceShop" class="org.springframework.aop.framework.ProxyFactoryBean">
  
<property name="proxyInterfaces">
    
<value>AdvisorTest.Shopping</value>
  
</property>
  
<property name="target">
    
<ref local="shoppingImpl"/>
  
</property>
  
<property name="interceptorNames">
    
<list>
      
<value>welcomeAdvice</value>
    
</list>
  
</property>
  
</bean>

<!-- 后置通知 -->
<bean id="thankyouAdvice" class="AdvisorTest.ThankYouAdvice"/>
<bean id="thankyouAdviceShop" class="org.springframework.aop.framework.ProxyFactoryBean">
  
<property name="proxyInterfaces">
    
<value>AdvisorTest.Shopping</value>
  
</property>
  
<property name="target">
    
<ref local="shoppingImpl"/>
  
</property>
  
<property name="interceptorNames">
    
<list>
      
<value>thankyouAdvice</value>
    
</list>
  
</property>
  
</bean>

<!-- 环绕通知 -->
<bean id="methodAdvice" class="AdvisorTest.MethodAdvisor"/>
<bean id="methodAdviceShop" class="org.springframework.aop.framework.ProxyFactoryBean">
  
<property name="proxyInterfaces">
    
<value>AdvisorTest.Shopping</value>
  
</property>
  
<property name="target">
    
<ref local="shoppingImpl"/>
  
</property>
  
<property name="interceptorNames">
    
<list>
      
<value>methodAdvice</value>
  
    
</list>
  
</property>
</bean>

<!-- 异常通知 -->
<bean id="exceptionAdvice" class="AdvisorTest.ExceptionAdvisor"/>
<bean id="exceptionAdviceShop" class="org.springframework.aop.framework.ProxyFactoryBean">
  
<property name="proxyInterfaces">
    
<value>AdvisorTest.Shopping</value>
  
</property>
  
<property name="target">
    
<ref local="shoppingImpl"/>
  
</property>
  
<property name="interceptorNames">
    
<list>
      
<value>exceptionAdvice</value>
  
    
</list>
  
</property>
</bean>
</beans>

 测试代码:

package AdvisorTest;

import java.io.File;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;



public class TestAdvisor ...{

    
public static void main(String[] args) ...{

        String filePath
=System.getProperty("user.dir")+File.separator+"AdvisorTest"+File.separator+"hello.xml";
        
        BeanFactory factory
=new XmlBeanFactory(new FileSystemResource(filePath));
        
        Shopping shopping
=null;
        System.out.println(
"不使用任何通知");
        shopping
=(Shopping)factory.getBean("shoppingImpl");
        shopping.buySomething(
"something");
        shopping.buyAnything(
"anything");
        
        System.out.println(
"使用前置通知");
        shopping
=(Shopping)factory.getBean("welcomeAdviceShop");
        shopping.buySomething(
"something");
        shopping.buyAnything(
"anything");
        
        System.out.println(
"使用后置通知");
        shopping
=(Shopping)factory.getBean("thankyouAdviceShop");
        shopping.buySomething(
"something");
        shopping.buyAnything(
"anything");
        
        System.out.println(
"使用环绕通知");
        shopping
=(Shopping)factory.getBean("methodAdviceShop");
        shopping.buySomething(
"something");
        shopping.buyAnything(
"anything");
        
        System.out.println(
"使用异常通知");
        shopping
=(Shopping)factory.getBean("exceptionAdviceShop");
        shopping.testException();
    

    }

}

 运行结果一目了然:

不使用任何通知
gaoxiang bye something success
gaoxiang bye anything success
使用前置通知
Hello welcome to bye something
gaoxiang bye something success
Hello welcome to bye anything
gaoxiang bye anything success
使用后置通知
gaoxiang bye something success
Hello Thankyou to bye something
gaoxiang bye anything success
Hello Thankyou to bye anything
使用环绕通知
this is beforesomething in MethodInterceptor
gaoxiang bye something success
this is aftersomething in MethodInterceptor
this is beforeanything in MethodInterceptor
gaoxiang bye anything success
this is afteranything in MethodInterceptor
使用异常通知
this is from exceptionAdvisor
2007-5-18 22:16:51 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from file [E:/项目/SpringInActionStudy/AdvisorTest/hello.xml]
Exception in thread "main" java.lang.ClassCastException
 at AdvisorTest.ShoppingImpl.testException(ShoppingImpl.java:22)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:585)
 at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:304)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:172)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:139)
 at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:126)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
 at $Proxy0.testException(Unknown Source)
 at AdvisorTest.TestAdvisor.main(TestAdvisor.java:42)

分享到:
评论

相关推荐

    Spring3_AOP四种创建通知(拦截器)类型

    Spring_AOP四种创建通知(拦截器)类型,介绍的比较详细,有实例

    spring_aop_拦截实例

    本实例主要探讨如何在Spring AOP中实现拦截器。 首先,我们来理解Spring AOP的基本概念。AOP的核心是代理,Spring提供了两种代理方式:JDK动态代理和CGLIB代理。JDK动态代理基于接口,当目标对象实现了接口时使用;...

    spring aop 拦截实例

    在提供的压缩包中,可能包含了一个或多个测试类(Tests),这些测试类通常用来验证AOP拦截器的功能。它们可能包含模拟业务场景的方法,这些方法会被切面拦截并执行相应的通知。通过运行这些测试,我们可以确保AOP...

    mybatis 拦截器 + spring aop切面 + spring事务+ 反射工具类

    例如,可能会有一个自定义的MyBatis拦截器用于分页查询,一个Spring AOP切面用于记录操作日志,Spring事务管理确保数据的一致性,而反射工具类可能用于动态加载配置或处理某些通用的反射任务。通过这些组件的组合,...

    Spring aop使用探究实例

    在Spring中,我们可以使用Advisor或拦截器来实现方面。 2. **连接点(Joinpoint)**:这是程序执行过程中的一个点,比如方法的执行或者异常的抛出。 3. **通知(Advice)**:当连接点被触发时,AOP框架执行的动作...

    SpringAOP结合ehCache实现简单缓存实例

    接下来,我们将讨论如何整合Spring AOP和EhCache来创建一个简单的缓存实例: 1. **引入依赖**:首先,你需要在项目的pom.xml文件中添加Spring AOP和EhCache的相关依赖。确保引入最新版本的Spring Framework和...

    spring-aop实例demo

    Spring AOP是基于代理的,它可以为普通Java对象(POJOs)提供拦截器模式的功能。本实例将详细介绍如何在Spring 3.2.8版本中实现AOP。 首先,我们需要理解AOP的基本概念。AOP的核心是切面(Aspect),它包含了通知...

    小马哥讲 Spring AOP 编程思想 - API 线索图.pdf

    - **Interceptor(拦截器)**:一个实现了特定接口的类,用来包装目标方法并执行额外的动作。 - **Proxy(代理)**:在目标对象和执行动作之间创建的一个对象,用于实现AOP功能。 2. AOP的不同类型的通知 - **...

    第四章:Spring AOP API 设计模式1

    7. **组合模式(Composite)**:在Spring AOP中,虽然没有直接的组合模式实现示例,但组合模式的思想体现在能够将多个拦截器(Interceptor)组合成一个链,每个拦截器都可以看作是树结构中的一个节点,共同完成一个...

    springioc和spring aop

    Spring框架是Java开发中不可或缺的一部分,它通过提供两种核心特性——控制反转(IoC)和面向切面编程(AOP)来简化应用的构建。理解并掌握这两种技术对于任何Java开发者来说都至关重要。 **控制反转(IoC)**,也...

    Spring源代码解析(七):Spring_AOP中对拦截器调用的实现.doc

    在Spring AOP中,拦截器调用的实现是通过动态代理机制来完成的,主要涉及到JDK的Proxy类和InvocationHandler接口。本文将详细解析Spring AOP如何利用这两个组件来实现拦截器链的调用。 首先,Spring在生成代理对象...

    spring aop jar

    Spring AOP支持五种不同类型的的通知: - **前置通知(Before)**:在目标方法执行之前执行。 - **后置通知(After)**:在目标方法执行之后执行,无论是否发生异常。 - **返回通知(After Returning)**:在目标...

    Spring_AOP_学习小结 Spring_AOP_学习小结 Spring_AOP_学习小结

    四、Spring AOP通知类型 1. BeforeAdvice(前置通知):在方法执行前调用,可以修改参数,抛出异常阻止方法执行。 2. AfterreturningAdvice(后返回通知):在方法正常返回后调用,不能修改返回值,但能抛出异常。...

    Spring之AOP配置文件详解

    从上述配置可以看出,Spring AOP主要是通过`ProxyFactoryBean`来创建代理对象,通过配置不同的拦截器来实现对目标对象方法的增强。这种配置方式非常灵活,可以根据实际需求动态地添加或修改拦截器,从而实现特定的...

    仿springAOP框架

    通知是在特定连接点(Join Point)执行的代码片段,根据执行时机的不同,分为前置通知、后置通知、异常通知、最终通知和环绕通知五种类型。在仿Spring AOP框架中,你可以定义各种通知方法,比如在方法执行前记录日志...

    JDK动态代理 spring aop 的原理

    总的来说,JDK动态代理是Spring AOP实现的基础,它允许我们在运行时动态创建代理对象,实现对方法调用的拦截和增强。Spring AOP则在此基础上提供了更高级的抽象,让我们可以方便地定义和管理切面,从而实现更灵活的...

    反射实现 AOP 动态代理模式(Spring AOP 的实现 原理) - Java 例子 -

    Spring AOP提供了五种不同类型的通知:前置通知(Before)、后置通知(After)、返回后通知(After Returning)、异常后通知(After Throwing)和环绕通知(Around)。 Spring AOP的实现方式主要有两种:静态代理和...

    java + spring boot +jpa 拦截器分库分表demo

    在Spring Boot中注册拦截器,我们需要在配置类中使用`@EnableAspectJAutoProxy`开启AOP代理,并通过`@Bean`注解声明拦截器实例。然后,使用`@Around`注解定义切点,即拦截所有的JPA操作。 在实际开发中,为了使分库...

    spring aop实例

    Spring AOP 主要支持两种类型的代理: 1. **JDK 动态代理**:主要用于实现接口的场景。 2. **CGLIB 代理**:用于增强没有实现接口的类。 #### 三、Spring AOP 关键概念 1. **切面(Aspect)**:是横切关注点的...

Global site tag (gtag.js) - Google Analytics