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 ...
随机推荐
- CSS3 文字渐变动画
背景剪裁 语法:background-clip: border-box || padding-box || context-box || no-clip || text 本次用到的就是: -webki ...
- jquery input选择器 语法
jquery input选择器 语法 作用::input 选择器选取表单元素.该选择器同样适用于 <button> 元素.大理石平台价格表 语法:$(":input") ...
- cordova打包遇到Connection timedout:
在cordova项目打包时,有时候处在公司内网环境,导致有些文件无法下载报下面的错误: A problem occurred configuring root project 'android'. & ...
- 51 Nod 1085 01背包问题
1085 背包问题 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 在N件物品取出若干件放在容量为W的背包里,每件物品的体积为W1,W2--Wn(Wi为 ...
- HGOI 20190519 题解
脑补了一下今天的比赛难度和之前zju-lzw出的题目画风迥异. 难度完全不是一个水平的好伐. Probem A palindrome 给出一个$n$个元素的数组,可以任意指定一个数字$m$让所有$a_ ...
- Android_(控件)Chronometer计时器
Android Chronometer(计时器) 继承TextView,显示的是某个时间点开始以及之后的时间增加 运行截图 程序结构 package com.example.administrator ...
- 上一个树形菜单的改进,增添了数据绑定功能而非仅仅的jq特效
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- mysql 查询近三个月数据
select * from t_user where time>DATE_SUB(CURDATE(), INTERVAL 1 WEEK) --一周 select * from t_user wh ...
- Apache配置转发
第一种: LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_htt ...
- linux下文件权限更改(转载)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qq_33571752/article/d ...