原理

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,其他人还是像往常一样编程。

  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框架一样,在运行时完成织入。

  各种通知类型包括:

  —  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代码  
  1. package com.test.TestSpring3;
  2. public interface UserService // 被拦截的接口
  3. ...{
  4. public void printUser(String user);
  5. }

实现类

Java代码  
  1. package com.test.TestSpring3;
  2. public class UserServiceImp implements UserService // 实现UserService接口
  3. ...{
  4. public void printUser(String user) ...{
  5. System.out.println("printUser user:" + user);// 显示user
  6. }
  7. }

AOP拦截器

Java代码    
  1. package com.test.TestSpring3;
  2. import org.aopalliance.intercept.MethodInterceptor;
  3. import org.aopalliance.intercept.MethodInvocation;
  4. public class UserInterceptor implements MethodInterceptor
  5. // AOP方法拦截器
  6. ...{
  7. public Object invoke(MethodInvocation arg0) throws Throwable ...{
  8. try ...{
  9. if (arg0.getMethod().getName().equals("printUser"))
  10. // 拦截方法是否是UserService接口的printUser方法
  11. ...{
  12. Object[] args = arg0.getArguments();// 被拦截的参数
  13. System.out.println("user:" + args[0]);
  14. arg0.getArguments()[0] = "hello!";// 修改被拦截的参数
  15. }
  16. System.out.println(arg0.getMethod().getName() + "---!");
  17. return arg0.proceed();// 运行UserService接口的printUser方法
  18. } catch (Exception e) ...{
  19. throw e;
  20. }
  21. }
  22. }

测试类

  1. package com.test.TestSpring3;
  2. import org.springframework.beans.factory.BeanFactory;
  3. import org.springframework.beans.factory.xml.XmlBeanFactory;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. import org.springframework.context.support.FileSystemXmlApplicationContext;
  7. import org.springframework.core.io.ClassPathResource;
  8. import org.springframework.core.io.Resource;
  9. import org.springframework.web.context.support.WebApplicationContextUtils;
  10. public class TestInterceptor ...{
  11. public static void main(String[] args) ...{
  12. ApplicationContext ctx = new FileSystemXmlApplicationContext(
  13. "classpath:applicationContext.xml");
  14. //        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  15. UserService us = (UserService) ctx.getBean("userService");
  16. us.printUser("shawn");
  17. }
  18. }

配置文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
  3. <beans>
  4. <bean id="userServiceImp"
  5. class="com.test.TestSpring3.UserServiceImp" />
  6. <bean id="userInterceptor" class="com.test.TestSpring3.UserInterceptor" />
  7. <bean id="userService"
  8. class="org.springframework.aop.framework.ProxyFactoryBean">
  9. <!-- 代理接口 -->
  10. <property name="proxyInterfaces">
  11. <value>com.test.TestSpring3.UserService</value>
  12. </property>
  13. <!-- 目标实现类 -->
  14. <property name="target">
  15. <ref local="userServiceImp" />
  16. </property>
  17. <!-- 拦截器 -->
  18. <property name="interceptorNames">
  19. <list>
  20. <value>userInterceptor</value>
  21. </list>
  22. </property>
  23. </bean>
  24. </beans>

输出:
  user:shawn
   printUser---!
  printUser user:hello!

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

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

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

  • 自动提交        这是JDBC驱动默认的模式,每次数据库操作(CRUD)成功完成后,都作为一个单独的事务自动提交,如果未成功完成,即抛出了 SQLException 的话,仅最近的一个操作将回滚。
  • 非自动提交    这是想更好的控制事务时需要程序地方式进行控制:
    • 在进行该事务单元的任何操作之前 setAutoCommit(false)
    • 在成功完成事务单元后 commit()
    • 在异常发生后 rollback()

自动提交模式是不被推荐的,因为每个操作都将产生一个事务点,这对于大的应用来说性能将受到影响;再有,对于常见的业务逻辑,这种模式显得无能为力。比如:
转帐,从A帐户取出100元,将其存入B帐户;如果在这两个操作之间发生了错误,那么用户A将损失了100元,而本来应该给帐户B的,却因为失败给了银行。
所以,建议在所有的应用中,如果使用 JDBC 都将不得不采用非自动提交模式(你们要能发现了在我们的 JDBC 那个例子中,我们采用的就是自动提交模式,我们是为了把精力放在JDBC上,而不是事务处理上),即我们不得不在每个方法中:

Java代码  
  1. try {
  2. // 在获得连接后,立即通过调用 setAutoCommit(false) 将事务处理置为非自动提交模式  // Prepare Query to fetch the user Information
  3. pst = conn.prepareStatement(findByName);
  4. // ...            conn.commit();
  5. }  catch(Exception ex) {
  6. conn.rollback();
  7. throw ex;
  8. }finally {
  9. try {
  10. // Close Result Set and Statement
  11. if (rset != null) rset.close();
  12. if (pst != null) pst.close();
  13. } catch (Exception ex) {
  14. ex.printStackTrace();
  15. throw new Exception("SQL Error while closing objects = " + ex.toString());
  16. }
  17. }

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

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

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.xsdhttp://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 hintfor 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代码  
  1. <aop:config>
  2. <!-- This definition creates auto-proxy infrastructure based on the given pointcut, expressed in AspectJ pointcut language.
  3. Here: applying the advice named        "txAdvice" to all methods on classes named PetStoreImpl. 指出在 PetStoreFacade
  4. 的所有方法都将采用 txAdvice(在紧接着的元素中定义了)事务方针,注意,我们这里虽然指定的是接口 PetStoreFacace,
  5. 但其暗示着其所有的实现类也将同样具有这种性质,因为本身就是实现类的方法在执行的,接口是没有方法体的。    -->
  6. <aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>
  7. <!-- 其它拦截机-->
  8. </aop:config>

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"/>

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 localhostprivate 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 setif (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 onlogger.warn("An exception occured when trying to send email", ex);}}}

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

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

3. 绿色的内容为这个 Advise 的核心,即在切入点被切入后将采用的动作。因为 Advise 也同样有多种类型,比如我们这里的“方法正常返回”,“方法执行前”,“方法执行后”,“环绕在方法执行前后”,“方法抛出异常时”等等(详情参见 Spring Reference: 6.2.4. Declaring advice)。但是我们的逻辑为在用户确认定单并且执行成功(所谓的成功是指将这一定单插入到了表 Order 中了)后,将发送一确认信。所以”方法正常返回“完全符合我们的要求。
接口AfterReturningAdvice 即是 Spring中表示”方法正常返回“ 这一语义的 Advice, 所以我们实现这个接口及其必须的方法 afterReturning.
方法代码的工作其实并不重要,只要我们理解这些“魔法”一样的技术后,实现代码是很简单的。值得提及的是这个方法的参数,这些参数是封装了切入点的所有信息,请见上面的注释。在我们的实现中只使用了被拦截方法的参数,在复杂的 Advice 实现中可能会用到切入点所有信息。

转载于:https://www.cnblogs.com/xtdxs/p/6527451.html

Spring AOP原理及拦截器相关推荐

  1. spring 两次进入拦截器_过滤器和拦截器的 6 个区别,别再傻傻分不清了

    点击上方 肉眼品世界,选择 设为星标 深度价值体系传递 作者 :程序员内点事 来源 :toutiao.com/i6834310440495874563 毕竟这两种工具开发中用到的频率都相当高,应用起来 ...

  2. modelandview使用过程_面试问烂的 Spring AOP 原理、Spring MVC 过程

    点击上方 Java后端,选择 设为星标 优质文章,及时送达 作者:莫那一鲁道链接:www.jianshu.com/p/e18fd44964eb Spring AOP ,SpringMVC ,这两个应该 ...

  3. 面试问烂的 Spring AOP 原理、SpringMVC 过程(求求你别问了)

    Spring AOP ,SpringMVC ,这两个应该是国内面试必问题,网上有很多答案,其实背背就可以.但今天笔者带大家一起深入浅出源码,看看他的原理.以期让印象更加深刻,面试的时候游刃有余. Sp ...

  4. spring过滤器Filter 、 拦截器Interceptor 、 切片Aspect 详解

    springboot 过滤器Filter vs 拦截器Interceptor vs 切片Aspect 详解 1 前言 最近接触到了过滤器和拦截器,网上查了查资料,这里记录一下,这篇文章就来仔细剖析下过 ...

  5. Spring MVC中的拦截器/过滤器HandlerInterceptorAdapter的使用

    转载自 https://www.cnblogs.com/EasonJim/p/7704740.html 一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的 而在Spring中,基于Filt ...

  6. spring mvc中的拦截器

    本文说下spring MVC中的拦截器 文章目录 拦截器介绍 拦截器注入适配器 自定义拦截器 controller测试 测试结果 本文小结 拦截器介绍 拦截器是在servlet执行之前执行的程序(这里 ...

  7. Spring的一种拦截器SimpleUrlHandlerMapping

    spring的一种拦截器,用于在XML文件中配置以拦截url,它是以map映射的方式进行拦截.映射是从前台urls到具体后台的beans.同时支持到bean实例和bean名称的映射,后者要求非单实例控 ...

  8. Struts2→拦截器、工作原理、拦截器计算Action执行时间、Struts2自带拦截器、拦截器栈

    工作原理 实现拦截器 样例 Struts2自带拦截器 拦截器栈(先进后出) TOKEN防表单重复提交 文字拦截器 AJAX

  9. 史上最烂 spring aop 原理分析

    盗引·中篇·spring aop spring aop: jdk 动态代理和 cglib 动态代理的特点.区别.使用方式.原理及各自对反射的优化.二者在 spring 中的统一.通知顺序.从 @Asp ...

最新文章

  1. 免费的python课程-自学Python的10门免费课程,已学完
  2. 微信JS-SDK使用步骤(以微信扫一扫为例)
  3. (JAVA学习笔记) 接口
  4. Android 通过代码改变控件的布局方式
  5. 经验:在mysql中避免重复插入数据的4种方式
  6. HTML5崛起之时,Java桌面时代就已经终结了
  7. ueditor添加下拉事件_Excel中最智能的三级下拉菜单!
  8. python编程(wx客户端编写)
  9. BUUCTF Web [ACTF2020 新生赛]Include
  10. Python入门(六) list
  11. QQ批量自动登录程序的设计
  12. Mysql解压版配置环境等
  13. ensp查看历史配置命令_学习华为ensp基本命令小技巧
  14. python dlib caffe人脸相似度_基于深度学习的人脸识别系统(Caffe+OpenCV+Dlib)【二】人脸预处理...
  15. 高仿微信 Windows 端
  16. 鸿蒙招聘店铺主是真的吗,为什么很多店铺门口贴着招聘,然而进去问都说招满了,但是招聘的内容还是放在那不收走?...
  17. 新版标准日本语初级_第二十三课
  18. numpy中的ndarray方法和属性
  19. CodeProject.AI 服务器:AI 最简单的方法
  20. 调用Nodejs版网易云API时,遇到code:-462报错解决方案

热门文章

  1. 山体等高线怎么看_怎么判断牙龈已经萎缩?
  2. javaio流_万字长文+思维导图帮你梳理 Java IO 流,还学不会你来打我(值得收藏)...
  3. vim编写代码时,文件末尾会多一个换行符的解决办法
  4. tensorlfow.saved_model的使用
  5. Java中需要全部小写的是,下列哪些是Java中常量的命名约定?A、全部为小写字母B、全部为大写字母C、大小写混合D、字与字之间...
  6. string s.substr()的用法
  7. 百练OJ:1013:Counterfeit Dollar(假币)
  8. 【项目管理】记第一次出差到客户现场推进项目验收感悟
  9. 【项目管理】Scrum内容整理
  10. 2020年信息系统项目管理师真题讲解