详解Spring AOP原理及拦截器,再有不懂者,请直接把这篇文章甩给他

Spring——AOP原理及流程详解 基于5.3.9 版本的Spring源码,对AOP原理及流程详解,AOP是在Bean生成流程中什么位置介入处理的?各个通知方法又是怎么组装的?AOP真的只是动态代理这么简单吗? 阅读详情

本文转载自:详解Spring AOP原理及拦截器,再有不懂者,请直接把这篇文章甩给他


一. 原理

AOP(Aspect Oriented Programming),也就是面向方面编程的技术。AOP基于IoC基础,是对OOP的有益补充。

AOP将应用系统分为两部分,核心业务逻辑(Core business concerns)及横向的通用逻辑,也就是所谓的方面Crosscutting enterprise concerns,例如,所有大中型应用都要涉及到的持久化管理(Persistent)、事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等。

AOP正在成为软件开发的下一个光环。使用AOP,你可以将处理aspect的代码注入主程序,通常主程序的主要目的并不在于处理这些aspect。AOP可以防止代码混乱。

Spring framework是很有前途的AOP技术。作为一种非侵略性的、轻型的AOP framework,你无需使用预编译器或其他的元标签,便可以在Java程序中使用它。这意味着开发团队里只需一人要对付AOP framework,其他人还是像往常一样编程。

1. AOP概念

让我们从定义一些重要的AOP概念开始。

方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。

连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。

通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。

切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。

引入(Introduction):添加方法或字段到被通知的类。Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现IsModified接口,来简化缓存。

目标对象(Target Object):包含连接点的对象,也被称作被通知或被代理对象。

AOP代理(AOP Proxy):AOP框架创建的对象,包含通知。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。

编织(Weaving):组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

2. 各种通知类型包括:

Around通知:包围一个连接点的通知,如方法调用。这是最强大的通知。Aroud通知在方法调用前后完成自定义的行为,它们负责选择继续执行连接点或通过返回它们自己的返回值或抛出异常来短路执行。

Before通知:在一个连接点之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。

Throws通知:在方法抛出异常时执行的通知。Spring提供强制类型的Throws通知,因此你可以书写代码捕获感兴趣的异常(和它的子类),不需要从Throwable或Exception强制类型转换。

After returning通知:在连接点正常完成后执行的通知,例如,一个方法正常返回,没有抛出异常。

Around通知是最通用的通知类型。大部分基于拦截的AOP框架(如Nanning和Jboss 4)只提供Around通知。

如同AspectJ,Spring提供所有类型的通知,我们推荐你使用最 为合适的通知类型来实现需要的行为。例如,如果只是需要用一个方法的返回值来更新缓存,你最好实现一个after returning通知,而不是around通知,虽然around通知也能完成同样的事情。使用最合适的通知类型使编程模型变得简单,并能减少潜在错 误。例如,你不需要调用在around通知中所需使用的MethodInvocation的proceed()方法,因此就调用失败。

切入点的概念是AOP的关键,它使AOP区别于其他使用拦截的技术。切入点使通知独立于OO的层次选定目标。例如,提供声明式事务管理的around通知可以被应用到跨越多个对象的一组方法上。 因此切入点构成了AOP的结构要素。

二. 拦截器(也称拦截机)

拦截机 (Interceptor), 是 AOP (Aspect-Oriented Programming) 的另一种叫法。AOP本身是一门语言,只不过我们使用的是基于JAVA的集成到Spring 中的 SpringAOP。同样,我们将通过我们的例子来理解陌生的概念。

接口类

Java代码

<span style="font-size: medium;">package com.test.TestSpring3;
public interface UserService // 被拦截的接口  
...{
	public void printUser(String user);
}
</span>

实现类

Java代码

<span style="font-size: medium;">package com.test.TestSpring3;
public class UserServiceImp implements UserService // 实现UserService接口  
...{
	public void printUser(String user) ...{
		System.out.println("printUser user:" + user);
		// 显示user
	}
}
</span>

AOP拦截器

Java代码

<span style="font-size: medium;">package com.test.TestSpring3;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class UserInterceptor implements MethodInterceptor  
	// AOP方法拦截器  
...{
	public Object invoke(MethodInvocation arg0) throws Throwable ...{
		try ...{
			if (arg0.getMethod().getName().equals("printUser"))  
				            // 拦截方法是否是UserService接口的printUser方法  
			...{
				Object[] args = arg0.getArguments();
				// 被拦截的参数  
				System.out.println("user:" + args[0]);
				arg0.getArguments()[0] = "hello!";
				// 修改被拦截的参数
			}
			System.out.println(arg0.getMethod().getName() + "---!");
			return arg0.proceed();
			// 运行UserService接口的printUser方法
		}
		catch (Exception e) ...{
			throw e;
		}
	}
}
</span><span style="font-size: medium;">  
	</span>

测试类

Java代码

<span style="font-size: medium;">package com.test.TestSpring3;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class TestInterceptor ...{
	public static void main(String[] args) ...{
		ApplicationContext ctx = new FileSystemXmlApplicationContext(  
			                "classpath:applicationContext.xml");
		//        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");      
		UserService us = (UserService) ctx.getBean("userService");
		us.printUser("shawn");
	}
}
</span><span style="font-size: medium;">  
	</span>

配置文件

Xml代码

<span style="font-size: medium;"><?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="userServiceImp"  
	        class="com.test.TestSpring3.UserServiceImp" />  
	    <bean id="userInterceptor" class="com.test.TestSpring3.UserInterceptor" />  
	    <bean id="userService"  
	        class="org.springframework.aop.framework.ProxyFactoryBean">  
	      <!-- 代理接口 -->  
	        <property name="proxyInterfaces">  
	            <value>com.test.TestSpring3.UserService</value>  
	        </property>  
	       <!-- 目标实现类 -->  
	        <property name="target">  
	            <ref local="userServiceImp" />   
	      </property>  
	        <!-- 拦截器 -->  
	        <property name="interceptorNames">  
	            <list>  
	                <value>userInterceptor</value>  
	            </list>  
	        </property>  
	    </bean>  
	</beans>  
	</span>

输出:

user:shawn
   printUser---!
  printUser user:hello!

结论:调用方法的时候 传入的值被拦截修改了.

三. 拦截器中的事务管理(事务拦截机)

如果不采用拦截机的机制时,在使用JDBC进行数据库访问时,存在两种情况:

自动提交:这是JDBC驱动默认的模式,每次数据库操作(CRUD)成功完成后,都作为一个单独的事务自动提交,如果未成功完成,即抛出了 SQLException 的话,仅最近的一个操作将回滚。

非自动提交:这是想更好的控制事务时需要程序地方式进行控制:

  • 在进行该事务单元的任何操作之前 setAutoCommit(false)
  • 在成功完成事务单元后 commit()
  • 在异常发生后 rollback()

自动提交模式是不被推荐的,因为每个操作都将产生一个事务点,这对于大的应用来说性能将受到影响;再有,对于常见的业务逻辑,这种模式显得无能为力。比如:

转帐,从A帐户取出100元,将其存入B帐户;如果在这两个操作之间发生了错误,那么用户A将损失了100元,而本来应该给帐户B的,却因为失败给了银行。

所以,建议在所有的应用中,如果使用 JDBC 都将不得不采用非自动提交模式(你们要能发现了在我们的 JDBC 那个例子中,我们采用的就是自动提交模式,我们是为了把精力放在JDBC上,而不是事务处理上),即我们不得不在每个方法中:

Java代码

<span style="font-size: medium;">try {      
	 // 在获得连接后,立即通过调用 setAutoCommit(false) 将事务处理置为非自动提交模式  // Prepare Query to fetch the user Information         
pst = conn.prepareStatement(findByName);
// ...            conn.commit();
}
catch(Exception ex) {
conn.rollback();
throw ex;
}
finally {
try {
	// Close Result Set and Statement    
	if (rset != null) rset.close();
	if (pst != null) pst.close();
}
catch (Exception ex) {
	ex.printStackTrace();
	throw new Exception("SQL Error while closing objects = " + ex.toString());
}
}
</span>

这样代码在AOP的倡导者看来是“肮脏”的代码。他们认为,所有的与事务有关的方法都应当可以集中配置(见声明性事务控制),并自动拦截,程序应当关心他们的主要任务,即商业逻辑,而不应和事务处理的代码搅和在一起。

我先看看 Spring 是怎么做到拦截的:

1. Spring 内置支持的事务处理拦截机

这里因为要用到JpetStore项目中的代码,我们将 applicationContext.xml 全部内容列出:

<?xml version="1.0" encoding="UTF-8"?>
<!--
  - Application context definition for JPetStore's business layer.
  - Contains bean references to the transaction manager and to the DAOs in
  - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation").
Jpetstore 的应用上下文定义,包含事务管理和引用了在 dataAccessContext-local/jta.xml(具体使用了哪个要看 web.xml 中的 'contextConfigLocation' 的配置)中注册的DAO
-->

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    <!-- ========================= GENERAL DEFINITIONS ========================= -->
    <!-- Configurer that replaces ${...} placeholders with values from properties files 
         占位符的值将从列出的属性文件中抽取出来
     -->
    <!-- (in this case, mail and JDBC related properties) -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>WEB-INF/mail.properties</value>
                <value>WEB-INF/jdbc.properties</value>
            </list>
        </property>
    </bean>
    <!-- MailSender used by EmailAdvice 
         指定用于发送邮件的 javamail 实现者,这里使用了 spring 自带的实现。此 bean 将被 emailAdvice 使用
     -->
    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="${mail.host}"/>
    </bean>
    <!-- ========================= BUSINESS OBJECT DEFINITIONS ======================== -->
    <!-- 不需要,因为被 SpringMVC 的实现使用 Generic validator for Account objects, to be used for example by the Spring web tier -->
    <bean id="accountValidator" class="org.springframework.samples.jpetstore.domain.logic.AccountValidator"/>
    <!-- 不需要,因为被 SpringMVC 的实现使用 Generic validator for Order objects, to be used for example by the Spring web tier -->
    <bean id="orderValidator" class="org.springframework.samples.jpetstore.domain.logic.OrderValidator"/>
    <!--
        主要的商业逻辑对象,即我们所说的门面对象
        注入了所有的DAO,这些DAO是引用了 dataAccessContext-xxx.xml 中定义的DAO
        门面对象中的所有方法的事务控制将通过下面的 aop:config 来加以控制
      - JPetStore primary business object (default implementation).
      - Transaction advice gets applied through the AOP configuration below.
   -->
    <bean id="petStore" class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="categoryDao" ref="categoryDao"/>
        <property name="productDao" ref="productDao"/>
        <property name="itemDao" ref="itemDao"/>
        <property name="orderDao" ref="orderDao"/>
    </bean>
    <!-- ========================= ASPECT CONFIGURATION ======================== -->
    <!-- AOP配置,用来控制哪些方法将需要进行事务处理,采用了AspectJ 的语法 -->
    <aop:config>
        <!--
        This definition creates auto-proxy infrastructure based on the given pointcut,
        expressed in AspectJ pointcut language. Here: applying the advice named
        "txAdvice" to all methods on classes named PetStoreImpl.
    -->
        <!-- 指出在 PetStoreFacade 的所有方法都将采用 txAdvice(在紧接着的元素中定义了)事务方针,注意,我们这里虽然指定的是接口 PetStoreFacace, 但其暗示着其所有的实现类也将
        同样具有这种性质,因为本身就是实现类的方法在执行的,接口是没有方法体的。 -->
        <aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>
        <!--
            This definition creates auto-proxy infrastructure based on the given pointcut,
            expressed in AspectJ pointcut language. Here: applying the advice named
            "emailAdvice" to insertOrder(Order) method of PetStoreImpl
    -->
        <!-- 当执行 PetStoreFacade.insertOrder方法,该方法最后一个参数为Order类型时(其实我们的例子中只有一个 insertOrder 方法,但这告诉了我们,当我们的接口或类中有重载了的方法,
        并且各个重载的方法可能使用不同的拦截机机制时,我们可以通过方法的参数加以指定),将执行emailAdvice(在最后定义的那个元素)-->
        <aop:advisor pointcut="execution(* *..PetStoreFacade.insertOrder(*..Order))" advice-ref="emailAdvice"/>
    </aop:config>
    <!--
     
        事务方针声明,用于控制采用什么样的事务策略
        Transaction advice definition, based on method name patterns.
        Defaults to PROPAGATION_REQUIRED for all methods whose name starts with
        "insert" or "update", and to PROPAGATION_REQUIRED with read-only hint
        for all other methods.
    -->
    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="insert*"/>
            <tx:method name="update*"/>
            <tx:method name="*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    <!-- 拦截机,用于在适当的时机(通过AOP配置,如上面)在方法执行成功后发送邮件
      AOP advice used to send confirmation email after order has been submitted -->
    <!-- -->
    <bean id="emailAdvice" class="org.springframework.samples.jpetstore.domain.logic.SendOrderConfirmationEmailAdvice">
        <property name="mailSender" ref="mailSender"/>
    </bean>
    <!-- ========================= 忽略 REMOTE EXPORTER DEFINITIONS ======================== -->
</beans>

这个配置比想象的要简单的多:

Xml代码

<span style="font-size: medium;"><aop:config>         
	 <!-- This definition creates auto-proxy infrastructure based on the given pointcut, expressed in AspectJ pointcut language.   
	Here: applying the advice named        "txAdvice" to all methods on classes named PetStoreImpl. 指出在 PetStoreFacade   
	的所有方法都将采用 txAdvice(在紧接着的元素中定义了)事务方针,注意,我们这里虽然指定的是接口 PetStoreFacace,          
	 但其暗示着其所有的实现类也将同样具有这种性质,因为本身就是实现类的方法在执行的,接口是没有方法体的。    -->     
	       <aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>                 
	 <!-- 其它拦截机-->    
	</aop:config>  
	</span>
  1. 所有的拦截机配置都放在 aop:config 配置元素中.
  2. 下面还是需要理解一下几个有关AOP的专用名词,不过,是挺抽象的,最好能会意出其的用意

pointcut:切入点,比如:updateAccount 方法需要进行事务管理,则这个切入点就是“执行方法体”(execution)。Spring 所有支持的切入点类型在都在 Spring reference: 6.2.3.1. Supported Pointcut Designators 中列出了。

advice:要对这个切入点进行什么操作,比如事务控制

advisor:Spring 特有的概念,将上两个概念合到一个概念中来,即一个 advisor 包含了一个切入点及对这个切入点所实施的操作。

因为 方法执行切入点 execution 为最常见的切入点类型,我们着重介绍一下,execution 的完全形式为:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

这是一个正则表达式,其中由 ‘?’ 结尾的部分是可选的。翻译过来就是:

执行(方法访问修饰符? 方法返回类型 声明类型? 方法名(方法参数类型) 抛出异常?)

所有的这些都是用来定义执行切入点,即那些方法应该被侯选为切入点:

  • 方法访问修饰符:即 public, private 等等
  • 方法返回类型:即方法返回的类型,如 void, String 等等
  • 声明类型:1.5的语法,现在可以先忽略它
  • 方法名:方法的名字
  • 方法参数类型:方法的参数类型
  • 抛出异常:方法声明的抛出的异常

例如,所有dao代码被定义在包 com.xyz.dao 及子包 com.xyz.dao.hibernate, 或者其它,如果还有的话,子包中, 里面定义的是提供DAO功能的接口或类,那么表达式:

execution(* com.xyz.dao..*.*(..))

表示切入点为:执行定义在包 com.xyz.dao 及其子包(因为 … 所致) 中的任何方法

详细情况可以参见 Spring refernce: 6.2.3.4. Examples

因此这个表达式为执行定义在类 PetStoreFacade 及其实现类中的所有方法,采取的动作定义在 txAdvice 中. 关于该 advice 的定义,(见声明性事务控制)一节

<aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>

2. Spring 自定拦截机

来为了进行事务控制,我们只需简单地配置几下,所有的工作都由 Spring 来做。这样固然很好,但有时我们需要有我们特有的控制逻辑。因为Spring 不可能包含所有人需要的所有拦截机。所以它提供了通过程序的方式加以定制的方式。我们的项目中就有这么一个拦截机,在用户确认付款后,将定单信息通过 email 的方式发送给注册用户的邮箱中。

<aop:config>
  ...
        <!-- 当执行 PetStoreFacade.insertOrder方法,该方法最后一个参数为Order类型时(其实我们的例子中只有一个 insertOrder 方法,但这告诉了我们,当我们的接口或类中有重载了的方法,并且各个重载的方法可能使用不同的拦截机机制时,我们可以通过方法的参数加以指定),将执行emailAdvice(在最后定义的那个元素)-->
        <aop:advisor pointcut="execution(* *..PetStoreFacade.insertOrder(*..Order))" advice-ref="emailAdvice"/>
    </aop:config>
红色的注释已经说的很清楚这个 Advisor 了,它的切入点(pointcut) 为 PetStoreFacade 的 void insertOrder(Order order) 方法,采取的动作为引用的 emailAdvice, 下面我们就来看看 emailAdvice:
    <bean id="emailAdvice" class="org.springframework.samples.jpetstore.domain.logic.SendOrderConfirmationEmailAdvice">
        <property name="mailSender" ref="mailSender"/>
    </bean>

它给了这个 advice 的实现类为 logic 包中 SendOrderConfirmationEmailAdvice, 该Bean 引用了我们前面定义的邮件发送器(一个 Spring 内置的邮件发送器).

下面看看这个实现类:

public class SendOrderConfirmationEmailAdvice implements AfterReturningAdvice, InitializingBean {
	// user jes on localhost
	private static final String DEFAULT_MAIL_FROM = "test@pprun.org";
	private static final String DEFAULT_SUBJECT = "Thank you for your order!";
	private final Log logger = LogFactory.getLog(getClass());
	private MailSender mailSender;
	private String mailFrom = DEFAULT_MAIL_FROM;
	private String subject = DEFAULT_SUBJECT;
	public void setMailSender(MailSender mailSender) {
		this.mailSender = mailSender;
	}
	public void setMailFrom(String mailFrom) {
		this.mailFrom = mailFrom;
	}
	public void setSubject(String subject) {
		this.subject = subject;
	}
	public void throws Exception {
		if (this.mailSender == null) {
			throw new IllegalStateException("mailSender is required");
		}
	}
	/**
     * 
     * @param returnValue 被拦截的方法的返回值
     * @param m 被拦截的方法的所有信息(Method类封装了这些信息)
     * @param args 被拦截的方法的所有参数组成的数组
     * @param target 目标对象,对于方法执行来说,即是方法所在的类的实例(与 this 同,批当前对象)
     * @throws java.lang.Throwable 
     */
	public void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable {
		// 我们被拦截的方法为 void insertOrder(Order order),方法只有一个参数,所以可知数据的第1个元素即是被传进的 order 对象
		// 得到了order 对象,就可以将 order 对应的帐户名及帐单号发送到邮件中,以便确认无误。
		Order order = (Order) args[0];
		Account account = ((PetStoreFacade) target).getAccount(order.getUser().getUsername());
		// don't do anything if email address is not set
		if (account.getEmail() == null || account.getEmail().length() == 0) {
			return;
		}
		StringBuffer text = new StringBuffer();
		text.append("Dear ").append(account.getFirstname()).
		                append(' ').append(account.getLastname());
		text.append(", thank your for your order from JPetStore. " +
		                "Please note that your order number is ");
		text.append(order.getId());
		SimpleMailMessage mailMessage = new SimpleMailMessage();
		mailMessage.setTo(account.getEmail());
		mailMessage.setFrom(this.mailFrom);
		mailMessage.setSubject(this.subject);
		mailMessage.setText(text.toString());
		try {
			this.mailSender.send(mailMessage);
		}
		catch (MailException ex) {
			// just log it and go on
			logger.warn("An exception occured when trying to send email", ex);
		}
	}
}

①. 红色的内容即为反向注入的 mailSender 属性

②. 蓝色的内容为 Spring Bean 的一个通用的接口 InitializingBean ,实现类需要实现该接口定义的方法 afterPropertiesSet() ,该方法中一般是在Bean 被初始化后并设置了所有的 setter 注入后调用的。所以这里是保证邮件发送器配置正确。因为如果没有配置正确,下面的工作是无法进行的,所以与其等那时抛出异常,还不如早早地在部署时就告知 (通过抛出 IllegalStateException 来提示)

③. 绿色的内容为这个 Advise 的核心,即在切入点被切入后将采用的动作。因为 Advise 也同样有多种类型,比如我们这里的“方法正常返回”,“方法执行前”,“方法执行后”,“环绕在方法执行前后”,“方法抛出异常时”等等(详情参见 Spring Reference: 6.2.4. Declaring advice)。但是我们的逻辑为在用户确认定单并且执行成功(所谓的成功是指将这一定单插入到了表 Order 中了)后,将发送一确认信。所以”方法正常返回“完全符合我们的要求。

接口AfterReturningAdvice 即是 Spring中表示”方法正常返回“ 这一语义的 Advice, 所以我们实现这个接口及其必须的方法 afterReturning.

方法代码的工作其实并不重要,只要我们理解这些“魔法”一样的技术后,实现代码是很简单的。值得提及的是这个方法的参数,这些参数是封装了切入点的所有信息,请见上面的注释。在我们的实现中只使用了被拦截方法的参数,在复杂的 Advice 实现中可能会用到切入点所有信息。


本文转载自:详解Spring AOP原理及拦截器,再有不懂者,请直接把这篇文章甩给他

Spring AOP概念及原理 Spring AOP 提供了强大的功能来增强 Bean 的行为,使得切面逻辑与核心业务逻辑分离,提升了代码的模块化和可维护性。在 Spring 中,AOP 的主要功能是为 Bean 增强功能,如添加额外的行为。在 JDK 动态代理中,InvocationHandler的invoke()方法包含了拦截器链的逻辑。代理对象的创建是在调用getProxy()方法时动态生成的,并且在这个方法中处理了所有的 AOP 增强逻辑。CGLIB 动态代理通过生成目标类的子类来实现代理,因此可以代理没有接口的类。 阅读详情

相关推荐

Spring深度解析-15、AOP拦截器链实现原理

在上一篇章的学习中了解到AOP代理对象的执行过程,AOP中的代理对象有JDK代理与CGLIB代理两种方式,这两种代理对象在对目标对象的方法进行拦截,分别通过JdkDynamicAopProxy的invoke和DynamicAdvisedInterceptor的intercept来拦截。 这两种的原理是一致的: 1、先判断有没有拦截器链,如果没有,那么直接执行目标对象的方法 2、如果有拦截器链,则封...

开始写bug~~~ 2218

Spring AOP(面向切面编程)和方法拦截

本文介绍了Spring AOP(面向切面编程)和方法拦截的概念、工作原理以及在实际开发中的应用。通过使用Spring AOP,可以将横切关注点从核心业务逻辑中分离出来,实现代码的模块化和可维护性。方法拦截是Spring AOP的一种常见用法,可用于实现日志记录、安全验证、性能监控、事务管理等功能。通过示例演示了如何配置和应用方法拦截器。Spring AOP和方法拦截为开发人员提供了一种灵活而强大的工具,可以提高代码的可读性、可维护性和可扩展性。希望本文对你理解和应用Spring AOP和方法拦截有所帮助。

tyxjolin的专栏 1552

Spring AOP拦截器实战:从基础到深入

在软件开发中,关注点的模块化是提高代码维护性和可重用性的重要手段。面向切面编程(Aspect-Oriented Programming, AOP)正是为此而设计的一种编程范式。Spring AOP作为Spring框架的一部分,提供了一种简洁的方式来实现AOP,它依赖于动态代理模式来拦截方法调用,并在方法执行前后的关键时刻插入额外的行为。核心概念包括切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等,它们共同构成了AOP的骨架。

weixin_35706255的博客 1099

Spring——Spring AOP原理

AOP即面向切面编程,是OOP编程的有效补充。使用AOP技术,可以将一些系统性相关的编程工作,独立提取出来,独立实现,然后通过切面切入进系统。从而避免了在业务逻辑的代码中混入很多的系统相关的逻辑.AOP是Spring提供的关键特性之一,本文深入剖析Spring AOP的原理。

庄小焱 3945

MOSFET高频响应实战:如何用LTspice仿真内部电容效应(附模型文件)

本文深入解析MOSFET高频响应中的内部电容效应,通过LTspice仿真工具详细展示如何提取模型参数并优化高频特性。从栅极相关电容到结电容的物理本质,再到实战案例中的开关损耗分析和频率响应扫描,提供全面的设计优化方法,帮助工程师有效应对高速开关电路中的电容挑战。

weixin_33725722的博客 390

WiseFlow本地搭建实录---保姆教程

本文介绍了如何从0开始搭建wiseflow的个人情报官的方法,目前所有的API全部都是免费的,对机器没有要求,大家可以放心搭建

liuhui244的博客 1962

Spring 框架之 AOP 原理剖析

前言 AOP(Aspect Oriented Programming)面向切面编程是 Spring 框架最核心的组件之一,它通过对程序结构的另一种考虑,补充了 OOP(Object-Oriented Programming)面向对象编程。在 OOP 中模块化的关键单元是类,而在 AOP 中,模块化单元是切面。也就是说 AOP 关注的不再是类,而是一系列类里面需要共同能力的行为。 本文内容主要包括:...

优快云 官方博客 6594

51单片机通过计时器实现倒计时

51单片机通过计时器操作两位8段阳极数码管,实现倒计时

一份耕耘,一分收获 3万+

Spring AOP原理详解及实例

Spring AOP原理详解及实例 1.Spring AOP简介 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻...

weixin_43611145的博客 2万+

Outlook总是提示登录微软,怎么办?

Outlook 2021反复弹出Microsoft登录窗口,可能是由于Modern Authentication身份验证机制或凭据问题导致。解决方案包括:1)通过注册表关闭Modern Authentication(适用于本地Exchange);2)清理Windows凭据管理器中的旧认证信息;3)手动配置Exchange服务器地址;4)通过注册表阻止Microsoft登录窗口弹出(适用于非M365环境)。建议按顺序尝试,尤其前两步通常能解决问题。经测试,步骤1和2已有效解决该问题。

剪刀石头布 4667

【仿真】Carla Python API实战:从零搭建自动驾驶测试环境

本文详细介绍了如何使用Carla Python API从零搭建自动驾驶测试环境。通过Carla仿真平台,开发者可以构建高度逼真的城市环境和车辆物理模型,利用Python API实现传感器配置、数据采集、场景构建及自动驾驶算法集成。文章还分享了实际项目中的调试技巧和性能优化经验,帮助读者快速掌握自动驾驶仿真测试的核心技术。

weixin_29050513的博客 213

Spring AOP MethodInvocation拦截器调用原理

前言 通过对JdkDynamicAopProxy的invoke方法的探究,发现invoke的核心是: 由匹配当前方法的advisor,例如与当前方法所匹配的所有before、afterReturning等增强,再将这些增强组成拦截器链 // 生产拦截器链 MethodInvocation invocation = new ReflectiveMethodInvocation(pro...

bugpool的博客 1万+

Vue3 - Element Plus 组件库 Tabs 标签页右侧区域插入按钮,<el-tabs> / <el-tab-pane> 选项卡组件右侧自定义插槽内容教程(右边区域添加自定义按钮功能区)

vue3,elementplus,tabs选项卡如何在插槽按钮,tabs标签页组件怎么自定义右侧内容,vue3elementplustabs组件右侧插槽按钮,element-plus在el-tabs组件的最右侧添加按钮,如何在选项卡右边加入按钮搜索框等内容,哪个属性能在tab选项卡右侧插入自定义按钮,在el-tabs组件最右侧添加按钮,vue3el-tabs组件怎么自定义右侧插槽内容,Tabs标签页右侧自定义插槽,ElementPlusTab右边加按钮,el-tabs组件自定义右侧按钮,在E

🏆 前端领域优质创作者 7016

Spring AOP 和 Spring 拦截器

拦截器(Interceptor)是 Spring MVC 提供的核心功能之一,主要作用是在请求到达 Controller 前后进行拦截和处理。实现@Slf4j@Component@Overridelog.info("preHandle - 目标方法执行前");// 返回 true 表示放行,false 表示拦截@Overridelog.info("postHandle - 目标方法执行后");@Overridelog.info("afterCompletion - 视图渲染完成后");

yualian的博客 1316

YOLOv13|损失函数优化篇:Focal EIOU 保持良好性能的同时,提供更高效的计算和更稳定的训练过程-包源码

Focal IoU与EIoU:目标检测中的损失函数优化 摘要:本文深入探讨了目标检测中两种重要的边界框回归损失函数优化方法。Focal IoU借鉴Focal Loss思想,通过(1-IoU)^γ因子调节损失权重,使模型更关注难样本(低IoU预测框),有效解决了传统IoU Loss对难易样本权重相同的问题。EIoU则在CIoU基础上改进,通过简化长宽比计算、分离宽高损失项,提升了计算效率和训练稳定性。两种方法分别从样本权重分配和损失函数结构优化角度,显著提升了目标检测性能,为实际应用提供了更高效的解决方案。文

FJN110的博客 1864

C#串口通信革命:RJCP.DLL.SerialPortStream实战全解析

本文介绍了如何通过RJCP.DLL.SerialPortStream库实现高性能串口通信解决方案。相比.NET自带的SerialPort类,该库提供了完全的异步非阻塞IO、动态缓冲区控制和多线程事件驱动等优势,特别适合工业自动化和物联网场景。文章详细讲解了环境搭建、核心功能对比,并通过代码示例展示了端口配置、异步通信管道搭建等关键技术。最后以Modbus RTU协议为例,演示了高级协议封装方法,为开发者提供了完整的工业级串口通信实现方案。

墨夶的博客 1871

Spring拦截器原理与实战详解

摘要:本文介绍了Spring MVC中拦截器的工作原理及实现方法。请求处理流程显示动态资源需先经过过滤器筛选,再通过中央控制器分发到Controller层。拦截器作为动态拦截机制,能在控制器方法前后执行预设代码。文章详细演示了拦截器实现步骤:1)创建实现HandlerInterceptor接口的类,定义preHandle、postHandle等方法;2)通过配置类注册拦截器并设置拦截路径。多个拦截器会形成拦截器链,按顺序执行。拦截器与过滤器的区别在于归属(Servlet/SpringMVC)和作用范围(所有

任岁月风干理想再也找不回真的我 2041

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

(精)Spring_AOP原理及拦截器

原理AOP(Aspect Oriented Programming),也就是面向方面编程的技术。AOP基于IoC基础,是对OOP的有益补充。  AOP将应用系统分为两部分,核心业务逻辑(Core businessconcerns)及横向的通用逻辑,也就是所谓的方面Crosscutting enterprise concerns,例如,所有大中型应用都要涉及到的持久化管理(Persistent)、事

it_man的专栏 3430

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

spring的拦截器和aop

探秘Spring AOP          AOP(Aspect Oriented Programming),即面向切面编程;通过预编译方式和运行期动态代理实现程序功能的统一维护的   一种技术。            AOP是什么?          1、AOP是一种编程范式,不是编程语言。          2、每一个切面目的是为了解决特定问题,不能解决所有的问题。      ...

qq_42025704的博客 2259

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

spring mvc拦截器,spring拦截器以及AOP切面的区别和源码

SpringMVC 拦截器执行时机 对于springmvc,有两种方式配置拦截器。 一是实现HandlerInterceptor接口,如 public class MyInterceptor1 implements HandlerInterceptor { //该方法在action执行前执行,可以实现对数据的预处理, // 比如:编码、安全控制等。如果方法返回true,则继续执行action。 @Override public boolean preHandle(HttpSe

qq_22162093的博客 2844

Spring AOP拦截器调用的实现

在Spring AOP通过jdk的proxy方式或者CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。 如果使用jdk的proxy来生成代理对象,那么需要通过InvocationHandler来设置拦截器回调。而如果使用CGLIB来生成代理对象,就需要根据CGLIB的使用要求,提供过DynamicAdvisedInterceptor来完成回调。 # 【1】JdkDynamicAopProxy的invoke拦截 JdkDynam

小小默:进无止境 1956

Spring AOP 拦截器链

Spring AOP 通过动态生成的代理类(使用 JDK 动态代理或 CGLIB)来拦截目标方法的调用,并根据配置的 Advisor 插入增强逻辑(Advice)。代理类的核心流程包括:匹配 Advisor 的 Pointcut,构建拦截器链,并依次执行 Advice(如 Around、Before、After 等),最终返回结果。代理类通过 MethodInvocation 对象管理拦截器链的执行,proceed() 方法递归调用每个 MethodInterceptor 的 invoke() 方法,形成类

红血哥 930

Spring AOP的原理是什么

Aspect

u012534547的博客 1202

Spring AOP 拦截器调用的实现

Spring AOP 拦截器调用的实现 文章目录Spring AOP 拦截器调用的实现前言相关文章项目环境1.设计原理2.JdkDynamicAopProxy 的 invoke 拦截3.CglibAopProxy 的 intercept 拦截4.目标对象方法的调用5.AOP拦截器链的调用6.配置通知器7.Advice通知的实现8.参考 前言 本篇是这个系列的正式内容最后一篇,主要是对拦截器相关设计原理介绍和具体实现源码的分析,也会和前面的内容串联起来进行回顾,加深印象。 相关文章 Spring AOP

谢文峰的博客 1658

Spring 常用的三种拦截器详解

我们介绍了一下spring中,常用的三种拦截器,以及他们在springboot中如何使用。最后给大家出一个小作业,如果把上面三个拦截器放到一个项目中,他会输出什么顺序呢?程序员博博引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构。

kfashfasf的博客 1593

Spring Boot中,拦截器和Spring AOP有什么区别

拦截器和AOP本质是互补技术:​拦截器是Web层的“门卫”,控制请求进出Controller。​AOP是业务层的“手术刀”,解耦非核心逻辑。实际项目中常结合使用,例如用拦截器校验登录状态,用AOP记录Service方法耗时。

java_beautiful的博客 840
上一篇: 精选74道JavaBAT面试题,助力"金三银四"面试季,详细解析无套路
下一篇: Java虚拟机工作原理详解
Java_supermanNO1
博客等级 码龄7年 1170粉丝 329原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值