spring aop之父子容器
AuthController
@RestController
public class AuthController { @PostMapping("authentication")
@TokenChecker
public Result getToken(String username,String password){
return null;
}
}
@Aspect
@Component
public class TokenAspect {
//匹配指定类下的有指定注解的方法。只要在要切入的方法上加上注解就可以将该方法作为切入点。
@Pointcut("execution (public * com.cotroller..*.*(..)) && @annotation(com.annotation.TokenChecker)")
public void addAdvice() {
} @Before("addAdvice()")
public void before() {
System.err.println("before");
} @After("addAdvice()")
public void after() {
System.err.println("after");
} }
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/applicationContext-mvc.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
applicationContext.xml关键配置信息
<aop:aspectj-autoproxy/>
<context:component-scan base-package="com"
name-generator="com.xxx">
<!-- 不扫描Controller注解 -->
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
<context:exclude-filter type="annotation"
expression="org.springframework.context.annotation.Configuration" />
</context:component-scan>
applicationContext-mvc.xml关键配置信息
<context:component-scan base-package="com"
use-default-filters="false">
<!-- 扫描controller注解 -->
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
<context:include-filter type="annotation"
expression="org.springframework.context.annotation.Configuration" />
</context:component-scan>
需要具备知识:
Spring 框架允许在一个应用中创建多个上下文容器。但是建议容器之间有父子关系。可以通过 ConfigurableApplicationContext 接口中定义的 setParent 方法设置父容器。一旦设置父子关系,则可以通过子容器获取父容器中除 PropertyPlaceHolder 以外的所有资源,父容器不能获取子容器中的任意资源(类似 Java 中的类型继承)。
1. 对于传统的web项目来说,通常使用spring和springmvc,因此对于这种项目来讲,他是有两个容器的,一个是spring容器,一般我们会把Service层的东西注入到spring容器中,另一个是springmvc的容器,通常这个容器里注入的是Controller层的东西,这里我们认为spring容器是父容器,springmvc是子容器的概念,然后我们大家都知道通过父子继承关系可知,子容器是可以读取到父容器中的东西,但是父容器是无法读到子容器中的内容,因此基于这个场景,有的同学,把Aop的实现类注入到了spring容器中,并且将Aop的切点表达式配置<aop:config> <aop:pointcut的execution也配到了spring容器的xml,而巧了这位同学要切的类方法,正好是Controller,也就是springmvc容器中的东西,那么这时候问题就来了,aop在初始化时会在自己的容器中寻找能够匹配的类方法,然后给他套上一层代理,此时他在自己能够访问到的spring容器中根本找不到与之匹配的类和方法,因为这些类和方法是在springmvc容器中管理的,因此就没有代理成功。
那么对于上述问题要怎么修改呢?只需要确保你要Aop切的类和方法与你Aop配置切点<aop:config> <aop:pointcut的execution表达式声明是在同一个容器中即可,此时只需要讲这个配置移到springmvc容器的xml中即可
2. 第二种情况与第一种情况有些许的类似,但并不相同,是关于重复扫描的,比如你在spring容器中配置了一个Aop,并且把他托管给spring容器管理,而且execution表达式切的也是spring容器中管理的类和方法,理论上这个时候是好用的,这批execution切到的类都被加了代理,但是巧了,springmvc容器中由于配置的是包路径扫描,恰好把execution表达式切的这一批对象又扫了一遍,又都托管给了springmvc容器,而此时扫到的这批对象,是重新new出来交给springmvc管理的,因此并没有被aop代理,所以在使用时,注入进来的可能是springmvc容器管理的这批对象,因此使用时发现Aop代理失效了。
这个问题的解决方案,就是避免两个容器重复扫描。
3. 第三个问题就比较简单了,他的现象是有些方法被Aop代理成功了,但有个别方法没有代理成功,究其原因发现这部分没有代理成功的方法并不是通过代理对象调用的,而是自身调用的,故被调用的方法没有被Aop代理,无法织入横切逻辑。
这个问题如果理解起来困难的话我举个例子,比如A.a(),A.b()是被代理的类和方法,那么当我调用A.a()时,此时a被代理了,成功执行代理类的内容,但还没有完,a()方法中调用了自身的方法b(),此时我们以为b也会被代理类代理,但实际上并没有,因为他是自身方法调用了并不是通过代理类A调用的,如果通过A.b()这种调用方式,那么b是可以被成功代理的。
分析:
1.我们的Controller类,使用注解@RestController,在applicationContext.xml中不扫描Controller注解的类,在applicationContext-mvc扫描Controller注解的类,结合web.xml可知我们的Controller AuthController被子容器管理。
2.我们的切面使用的注解是@Aspect和@Component, 结合 applicationContext.xml与web.xml可知,切面实例被父容器管理。
3.解决 因为我们切面类中使用的@Component注解会被Spring父容器管理,不适用注解,在application-mvc.xml中使用xml方法方式实例化切面类。这样Controller和切面类在同一个容器中管理,就可以正常的进行aop代理。
错误的尝试:
1.Controller使用@Component注解,想让其鬼父容器管理这样Controller和切面就归同一个容器管理了:这时候通过postman访问接口请求失败。
2.切面类,使用@Controller 还是没有进入切面类。看到配置中不但把Controller注解还有Configuration注解都归子容器管理,把切面类的注解改为@Configuration同样还是没有进入切面。
总结:
1.分析的问题的时候,注意web.xml的重要性,好多问题都可以从web.xml 这个配置文件开始往后面推。
2.深刻的理解一下父子容器的关系。哪些注解的类初始化后被父容器管理,哪些被子容器管理。
3. 动态代理 JDK与CGLIB的区别。我这个项目中就有一个被final修饰的Controller。导致在设置代理方式的出错。在不同的配置文件中设置代理方式应该是对加载这个配置的容器管理的类有影响,对别的容器不影响。
spring aop之父子容器的更多相关文章
- spring与springmvc父子容器
转载地址:http://www.tianshouzhi.com/api/tutorials/spring 1.spring和springmvc父子容器概念介绍 在spring和springmvc进行整 ...
- Spring和springMVC父子容器的关系
部分转载自:https://www.cnblogs.com/ljdblog/p/7461854.html springMVC容器和Spring容器 为什么一定要在web.xml中配置spring的li ...
- (转载)Spring与SpringMVC父子容器的关系与初始化
转自 https://blog.csdn.net/dhaiuda/article/details/80026354 Spring和SpringMVC的容器具有父子关系,Spring容器为父容器,Spr ...
- 1、spring与springmvc父子容器
转载于http://www.tianshouzhi.com/api/tutorials/spring 1.0 spring与springmvc父子容器 1.spring和springmvc父子容器概念 ...
- spring和springmvc父子容器关系
一般来说,我们在整合spring和SpringMVC这两个框架中,web.xml会这样写到: <!-- 加载spring容器 --> <!-- 初始化加载application.xm ...
- 面试高频题:说一说对Spring和SpringMvc父子容器的理解?
引言 以前写了几篇关于SpringBoot的文章<面试高频题:springBoot自动装配的原理你能说出来吗>.<保姆级教程,手把手教你实现一个SpringBoot的starter& ...
- Spring和SpringMVC父子容器关系初窥
一.背景 最近由于项目的包扫描出现了问题,在解决问题的过程中,偶然发现了Spring和SpringMVC是有父子容器关系的,而且正是因为这个才往往会出现包扫描的问题,我们在此来分析和理解Spring和 ...
- 转:spring的启动过程-spring和springMVC父子容器的原理
要想很好理解这三个上下文的关系,需要先熟悉spring是怎样在web容器中启动起来的.spring的启动过程其实就是其IoC容器的启动过程,对于web程序,IoC容器启动过程即是建立上下文的过程. s ...
- Spring和springmvc父子容器注解扫描问题详解
一.Spring容器和springmvc容器的关系如下图所示: Spring和springmvc和作为两个独立的容器,会把扫描到的注解对象分别放到两个不同的容器中, Springmvc容器是spr ...
随机推荐
- 什么是JavaScript循环结构?
㈠什么是循环结构 ⑴什么是循环? 反复一遍又一遍的做着相同(相似)的事情 ⑵循环中的两大要素 ①循环条件:什么时候开始,什么时候结束 ②循环操作:循环体,循环过程中,干了什么 ㈡循环结构—while循 ...
- HTML的<form>表单标签
表单 HTML 表单用于搜集不同类型的用户输入. ㈠Form标签 ⑴form标签简介 在HTML中,如果创建一个表单,就把各种表单标签放在<form></form>标签内部.我 ...
- TTTTTTTTTTTT CF 653D 送邮递员
链接:给一张n个点m条带权边的有向图,有x个人从起点出发到终点,每个人带的都带相同重量的货物, 规定一条边最多能经过其上权的重量的货物,问最多能带多重的货物? 2 ≤ n ≤ 50, 1 ≤ m ≤ ...
- Tarjan求LCA胡乱写的板子 x
首先Tarjan算法的基本思路: 1.任选一个点为根节点,从根节点开始. 2.遍历该点u所有子节点v,并标记这些子节点v已被访问过. 3.若是v还有子节点,继续搜索下去,否则下一步. 4.合并v到u上 ...
- Python argparse 用法总结
使用argparse的四个基本步骤 创建 ArgumentParser() 对象 调用 add_argument() 方法添加参数 使用 parse_args() 解析添加的参数 # example ...
- Redis大 key的发现与删除方法全解析
个推作为国内第三方推送市场的早期进入者,专注于为开发者提供高效稳定的推送服务,经过9年的积累和发展,服务了包括新浪.滴滴在内的数十万APP.由于我们推送业务对并发量.速度要求很高,为此,我们选择了高性 ...
- java 获取文本一行一行读
直接上代码: 如果出现乱码:请改一下编码:我这里使用utf-8是会乱码的,改GBK就好了 // 读取文件内容 public static String readFile(String path) {/ ...
- 6张图解释IO流
1.字节流InputStream 2.字节流OutputStream 3.字符流Reader 4.字符流Writer 5.节点流 6.处理流 总结: 节点流可以直接连接在数据源上,处理流不可以:节点流 ...
- python3笔记十五:python函数
一:学习内容 函数概述 函数的参数与返回值 参数值传递和引用传递 关键字参数 默认参数 不定长参数 二:函数概述 1.本质:函数就是对功能的封装 2.优点: 简化代码结构,增加了代码的复用度(重复使用 ...
- Android 6.0动态权限申请
转载(Android 6.0 动态权限申请简单简洁优雅的处理方式): https://blog.csdn.net/lin_dianwei/article/details/79025324