首页 > 其他分享 >spring AOP和通知

spring AOP和通知

时间:2023-04-23 11:03:52浏览次数:36  
标签:spring Object 通知 aop println AOP public out


1.  spring的通知

1.1.  AOP的概念

切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式或者基于注解的方式来实现。

连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。

通知(Advice):在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。

切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。

引入(Introduction):用来给一个类型声明额外的方法或属性(也被称为连接类型声明(inter-type declaration))。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用引入来使一个bean实现IsModified接口,以便简化缓存机制。

目标对象(Target Object): 被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。

AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。

织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

1.2.  通知

通知类型

接口

描述

Around

org.aopalliance.intercept.

MethodInterceptor

拦截对目标方法调用

Before

Org.springframework.aop.

MethodBeforeAdvice

在目标方法调用前调用

After

Org.springframework.aop.

AfterReturningAdvice

在目标方法调用后调用

Throws

Org.springframework.aop.

ThrowsAdvice

当目标方法抛出异常时调用

1.2.1.  前置通知

Org.springframework.aop.MethodBeforeAdvice接口的代码如下:

public  abstract interface MethodBeforeAdvice extends BeforeAdvice {
         public  abstract void before(Method  paramMethod,
paramArrayOfObject, Object paramObject) throws Throwable;
}

注意返回值的类型是void。前置通知可以在连接点执行之前插入自定义行为,但是不能修改连接点的返回值。如果一个前置通知抛出异常,这将中止拦截器链的进一步执行。异常将沿着拦截器链向回传播。如果异常是非强制检查的(unchecked)或者已经被包含在被调用方法的throws声明中,它将被直接返回给客户端;否则它将由AOP代理包装在一个非强制检查异常中返回。

1.2.2.  后置通知

Org.springframework.aop.AfterReturningAdvice接口的代码如下:

public abstract interface AfterReturningAdvice extends AfterAdvice {
         public abstract void afterReturning(Object paramObject1,
                            Method paramMethod, Object[] paramArrayOfObject, Object paramObject2)
                            throws Throwable;
}

后置通知可以访问返回值(但不能进行修改),被调用方法,方法参数以及目标对象。

1.2.3.  环绕通知

public abstract interface MethodInterceptor extends Callback {
         public abstract Object intercept(Object paramObject, Method paramMethod,
                            Object[] paramArrayOfObject, MethodProxy paramMethodProxy)
                            throws Throwable;
}

invoke()方法的MethodInvocation参数暴露了被调用的方法,目标连接点,AOP代理以及传递给方法的参数。invoke()方法应该返回调用的结果:即连接点的返回值。注意对MethodInvocation中proceed()方法的调用。这个方法继续运行指向连接点的拦截器链并返回proceed()的结果。大多数拦截器会调用这个方法,返回一个值。然而,一个类似任意环绕通知的MethodInterceptor,可以返回一个不同的值或者抛出一个异常而不是调用proceed方法。

1.2.4.  异常通知

如果连接点抛出异常,异常通知(throwsadvice)将在连接点返回后被调用。 Spring提供类型检查的异常通知(typed throws advice),这意味着org.springframework.aop.ThrowsAdvice接口不包含任何方法: 它只是一个标记接口用来标识所给对象实现了一个或者多个针对特定类型的异常通知方法。这些方法应当满足下面的格式:

afterThrowing([Method, args, target], subclassOfThrowable)

只有最后一个参数是必须的。根据异常通知方法对方法及参数的需求,方法的签名可以有一个或者四个参数。下面是一个异常通知的例子。

当一个RemoteException(包括它的子类)被抛出时,下面的通知会被调用:

public class RemoteThrowsAdvice implements ThrowsAdvice {
 
    public void afterThrowing(RemoteException ex) throws Throwable {
                // Do something with remote exception
    }
            }

1.2.5.  通知使用实例

1)        使用新建eclipse新建一个java web工程,引入spring jar包

2)        新建一个实现了前置通知接口的类BeforeAdvice类

package com.morris.spring.aop;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.springframework.aop.MethodBeforeAdvice;
public class BeforeAdvice implements MethodBeforeAdvice {
 
         public void before(Method paramMethod, Object[] paramArrayOfObject,
                            Object paramObject) throws Throwable {
 
                   System.out.println("。。。。前置通知开始。。。。");
                   System.out.println("要执行的方法:"+paramMethod.getName());
                   System.out.println("参数:"+Arrays.toString(paramArrayOfObject));
                   System.out.println("目标对象:"+paramObject);
                   System.out.println("。。。。前置通知结束。。。。");
 
         }
 
}

3)        新建一个实现了后置通知接口的类AfterAdvice

package com.morris.spring.aop;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.springframework.aop.AfterReturningAdvice;
public class AfterAdvice implements AfterReturningAdvice {
 
         public void afterReturning(Object paramObject1, Method paramMethod,
                            Object[] paramArrayOfObject, Object paramObject2) throws Throwable {
                   
                   System.out.println("后置通知开始。。。。");
                   System.out.println("返回值:"+paramObject1);
                   System.out.println("执行方法:"+paramMethod.getName());
                   System.out.println("参数:"+Arrays.toString(paramArrayOfObject));
                   System.out.println("目标对象:"+paramObject2);
                   System.out.println("后置通知结束。。。。");
 
         }
 
}

4)        新建一个实现了环绕通知接口的类RoundAdvice

package com.morris.spring.aop;
 
import java.lang.reflect.Method;
import java.util.Arrays;
 
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
 
public class RoundAdvice implements MethodInterceptor {
 
         public Object invoke(MethodInvocation invocation) throws Throwable {
                   System.out.println("--环绕通知开始------");
                   Method method = invocation.getMethod();
                   System.out.println("执行的方法:" + method.getName());
                   Object[] parameters = invocation.getArguments();
                   System.out.println("参数:" + Arrays.toString(parameters));
                   Object obj = invocation.proceed();
                   System.out.println("--环绕通知结束-----");
                   return obj;
 
         }
}

5)        新建目标对象所需实现的接口IHello

package com.morris.spring.aop;
public interface IHello {
         String sayHello(String name);
}

6)        新建一个目标对象HelloImpl

package com.morris.spring.aop;

public class HelloImpl implements IHello {

         public String sayHello(String name) {

                   System.out.println("********执行目标方法***********");

                   return "Hello " + name;

         }

}

7)        编写spring的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- - Middle tier application context definition for the image database. -->
<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-2.5.xsd
                                     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                                     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
         <!-- 前置对象 -->
         <bean id="beforeAdvice" class="com.morris.spring.aop.BeforeAdvice"></bean>
         <!-- 后置对象 -->
         <bean id="afterAdvice" class="com.morris.spring.aop.AfterAdvice"></bean>
         <!-- 环绕通知 -->
         <bean id="roundAdvice" class="com.morris.spring.aop.RoundAdvice"></bean>
         <!-- 目标对象 -->
         <bean id="hello" class="com.morris.spring.aop.HelloImpl"></bean>
         <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
                   <!-- 引用目标对象 -->
                   <property name="target" ref="hello"></property>
                   <!-- 要代理的接口,目标对象实现的接口 -->
                   <property name="proxyInterfaces">
                            <list>
                                     <value>com.morris.spring.aop.IHello</value>
                            </list>
                   </property>
                   <!-- 拦截器,所有的通知 -->
                   <property name="interceptorNames">
                            <list>
                                     <value>beforeAdvice</value>
                                     <value>afterAdvice</value>
                                     <value>roundAdvice</value>
                            </list>
                   </property>
 
         </bean>
</beans>

8)        编写测试类Test

package com.morris.spring.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
         public static void main(String[] args) {
                   // 加载spring配置文件
                   ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                                     "spring.xml");
                   // 获得目标对象
                   IHello hello = (IHello) applicationContext.getBean("proxy");
                   // 执行目标对象方法
                   hello.sayHello("morris");
         }
}

运行结果如下:

。。。。前置通知开始。。。。

要执行的方法:sayHello

参数:[morris]

目标对象:com.morris.spring.aop.HelloImpl@1bb7be

。。。。前置通知结束。。。。

--环绕通知开始------

执行的方法:sayHello

参数:[morris]

********执行目标方法***********

--环绕通知结束-----

后置通知开始。。。。

返回值:Hello morris

执行方法:sayHello

参数:[morris]

目标对象:com.morris.spring.aop.HelloImpl@1bb7be

后置通知结束。。。。

 

标签:spring,Object,通知,aop,println,AOP,public,out
From: https://blog.51cto.com/u_6784072/6216860

相关文章

  • Spring与Hibernate的整合
    1.Spring与Hibernate的整合1.1.在Spring容器中创建SessionFactory为了避免硬编码的资源查找与应用程序对象紧密耦合,Spring允许你在Spring容器中以bean的方式定义诸如JDBCDataSource或者HibernateSessionFactory的数据访问资源。任何需要进行资源访问的应用程序对象只需要持有......
  • spring mvc一个Controller响应多个请求
    1.1. 控制器的实现packagecom.morris.controller;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.springframework.web.servlet.ModelAndView;importorg.springframework.web.servlet.mvc.multiaction.Multi......
  • spring集成Hessian
    1.1.1.   编写远程接口Ihello.javapackagecn.tempus.hessian;publicinterfaceIHello{publicStringsayHello(Stringname);}1.1.2.   编写远程接口实现类HelloImpl.javapackagecn.tempus.hessian;importcom.caucho.hessian.server.HessianServlet;......
  • spring mvc注解基本配置
    1.1. 配置web.xml<?xmlversion="1.0"encoding="UTF-8"?><web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xm......
  • 【spring boot】 重启kafka客户端连接
    背景kafka服务端重建时,kafka客户端会连不上kafka服务端,此时需要重启客户端重连代码实现@ServicepublicclassKafkaConsumerService{privateKafkaConsumer<String,String>consumer;@AutowiredprivateKafkaPropertieskafkaProperties;//在应用......
  • Spring缓存注解的使用与源码分析
    SpringCache提供了一个对缓存使用的抽象,以及大量的实现方便开发者使用。SpringCache主要提供了如下注解:注解说明@Cacheable根据方法的请求参数对其结果进行缓存@CachePut根据方法的请求参数对其结果进行缓存,和@Cacheable不同的是,它每次都会触发真实方法的调用@CacheEvict根据一定......
  • SpringMVC启动流程源码分析
    SpringMVC向WEB容器中注入了两个对象:ContextLoaderListener:由AbstractContextLoaderInitializer注入。DispatcherServlet:由AbstractDispatcherServletInitializer注入。下面分别分析这两个对象在WEB容器启动时做了什么工作?ContextLoaderListenerContextLoaderListener实现了Servle......
  • 为spring boot定制启动banner
    直接打开这个网站 https://patorjk.com/software/taag/#p=testall&f=Larry%203D&t=Type%20Something%20 输入你想要的文字内容,点TestAll即可,我们这里选择的字体是:Larry3D,你也可以根据喜好,选择自己想要的字体 复制并保存到src/main/resources/banner.txt即可 参考资料:......
  • spring boot配置mybatis出现Invalid bound statement (not found)报错的解决办法
     背景:spring-boot-starter-parent2.5.6mybatis-spring-boot-starter2.2.0我遇到这个报错,是因为使用idea创建xml文件是没有后缀,举个例子,比如你创建的是AccountMapper.xml,结果使用idea创建的是AccountMapper,根本就没有后缀!解决办法也很简单,加上后缀就可以了,不需要做其他额外的......
  • SpringDay01-入门基础知识、Bean的配置(一)
    Spring(黑马)一、基础知识1.1传统JavaWeb的缺点传统的JavaWeb在实现某个主要的业务逻辑时需要做的事情:new一个实现类对象,然后通过对象调用某个主要的方法;开启事务、提交事务、回滚事务;在日志中记录修改数据;在日志中记录异常数据等。以上传统方法带来的问题:实现类与接......