shiro的DelegatingFilterProxy怎么找到ShiroFilterFactoryBean
首先看到web.xml中的配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
<!-- 这里配置你的ShiroFilterFactoryBean的spring配置文件 -->
</param-value>
</context-param>
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
现在就引出一个问题,这里配置了ShiroFilterFactoryBean 和 DelegatingFilterProxy对象,显然这两个只是一个工厂Bean和一个委托代理对象 那么真正的shiro入口过滤器在哪儿 ?
我们进入DelegatingFilterProxy
发现其构造方法是空的
public DelegatingFilterProxy() {
}
但是它的父类GenericFilterBean实现了InitializingBean, 那么就多了个afterPropertiesSet方法
GenericFilterBean
@Override
public void afterPropertiesSet() throws ServletException {
initFilterBean();
}
DelegatingFilterProxy
@Override
protected void initFilterBean() throws ServletException {
synchronized (this.delegateMonitor) {
if (this.delegate == null) {
// 这个是DelegatingFilterProxy配置的名字 shiroFilter
if (this.targetBeanName == null) {
this.targetBeanName = getFilterName();
}
WebApplicationContext wac = findWebApplicationContext();
if (wac != null) {
//初始化
this.delegate = initDelegate(wac);
}
}
}
}
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
//从spring上下文中根据shiroFilter(DelegatingFilterProxy配置的名字) 获取bean
Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
if (isTargetFilterLifecycle()) {
delegate.init(getFilterConfig());
}
return delegate;
}
AbstractApplicationContext
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name, requiredType);
}
AbstractBeanFactory
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
//最终走到了doGetBean
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException { final String beanName = transformedBeanName(name);
Object bean; // 根据web里面配置的shiroFilter的名字在spring容器中获取到了ShiroFilterFactoryBean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// 通过工厂获取对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}return (T) bean;
}
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { //其中有这么一句,从工厂Bean中获取Bean实例
if (object == null) {
...
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
FactoryBeanRegistrySupport 经过枯燥的源码调用 ,来到了大门口
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException { Object object;
try {
else {
//调用ShiroFilterFactoryBean的getObjectct方法, ShiroFilterFactoryBean实现了FactoryBean
object = factory.getObject();
}
}
return object;
}
现在让我们来看看ShiroFilterFactoryBean
public Object getObject() throws Exception {
if (instance == null) {
instance = createInstance();
}
return instance;
}
protected AbstractShiroFilter createInstance() throws Exception {
SecurityManager securityManager = getSecurityManager();
//这里有个创建过滤连管理器的方法 我们也要看看
FilterChainManager manager = createFilterChainManager();
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
chainResolver.setFilterChainManager(manager);
//这里就是最终的那个shiro的入口Filter 是 AbstractShiroFilter的子类
return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
}
那么SpringShiroFilter就长这样,这个就是shiro的入口Filter,每次调用都会先调用它(doFilter方法在父类AbstractShiroFilter 中)
private static final class SpringShiroFilter extends AbstractShiroFilter {
protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
super();
if (webSecurityManager == null) {
throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
}
setSecurityManager(webSecurityManager);
if (resolver != null) {
setFilterChainResolver(resolver);
}
}
}
然后我们再看看createFilterChainManager
protected FilterChainManager createFilterChainManager() {
//其中包含了11个默认的过滤器
DefaultFilterChainManager manager = new DefaultFilterChainManager();
//默认的11个过滤器
Map<String, Filter> defaultFilters = manager.getFilters();
// 添加登陆、登陆成功、没有认证 的url(如果设置了的话)
for (Filter filter : defaultFilters.values()) {
applyGlobalPropertiesIfNecessary(filter);
} /在xml文件的<property name="filters">中配置的过滤
Map<String, Filter> filters = getFilters();
if (!CollectionUtils.isEmpty(filters)) {
for (Map.Entry<String, Filter> entry : filters.entrySet()) {
//拦截规则
String name = entry.getKey();
//过滤器
Filter filter = entry.getValue();
// 添加登陆、登陆成功、没有认证 的url(如果设置了的话)
applyGlobalPropertiesIfNecessary(filter);
//设置名字
if (filter instanceof Nameable) {
((Nameable) filter).setName(name);
}
//添加自定义的过滤器, 因为spring容器启动时初始化过自定义的过滤器,所以这个为初始化参数为false
manager.addFilter(name, filter, false);
}
} //<property name="filterChainDefinitions">中设置的规则与过滤器
Map<String, String> chains = getFilterChainDefinitionMap();
if (!CollectionUtils.isEmpty(chains)) {
//绑定规则与过滤器链
for (Map.Entry<String, String> entry : chains.entrySet()) {
//规则
String url = entry.getKey();
//过滤器链中的过滤器名称
String chainDefinition = entry.getValue();
//创建过滤器链
manager.createChain(url, chainDefinition);
}
} return manager;
}
// 给 “每一个” 满足类型的过滤器添加添加登陆、登陆成功、没有认证 的url(如果设置了的话)
private void applyGlobalPropertiesIfNecessary(Filter filter) {
// 需要是AccessControlFilter类型
applyLoginUrlIfNecessary(filter);
// 需要是 AuthenticationFilter类型
applySuccessUrlIfNecessary(filter);
//需要是AuthorizationFilter 类型
applyUnauthorizedUrlIfNecessary(filter);
}
DefaultFilterChainManager
//创建过滤链
public void createChain(String chainName, String chainDefinition) {
// 过滤器可以写成这样 { "authc", "roles[admin,user]", "perms[file:edit]" }
String[] filterTokens = splitChainDefinition(chainDefinition); //这里让每一个PathConfigProcessor类型的过滤器都有该过滤器对应的所有规则 这里遍历的是过滤链字符串
for (String token : filterTokens) {
String[] nameConfigPair = toNameConfigPair(token);
//添加过滤器到过滤链(一个规则对应一条过滤链)
addToChain(chainName, nameConfigPair[0], nameConfigPair[1]);
}
}
//添加过滤器到过滤链
public void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) {
//根据名称获取过滤器
Filter filter = getFilter(filterName);
//配置过滤链
applyChainConfig(chainName, filter, chainSpecificFilterConfig); NamedFilterList chain = ensureChain(chainName);
chain.add(filter);
}
//配置过滤链
protected void applyChainConfig(String chainName, Filter filter, String chainSpecificFilterConfig) {
//如果当前过滤器是PathConfigProcessor类型 处理之
if (filter instanceof PathConfigProcessor) {
((PathConfigProcessor) filter).processPathConfig(chainName, chainSpecificFilterConfig);
}
}
PathMatchingFilter 这里将同一过滤器的所有规则设置给当前过滤器 比如 /aa=anon /bb=anon 如果当前请求的路径是/aa 它对应的过滤器是anon 这里的appliedPaths就会有 /aa 和 /bb两个元素
简单理解为当前拦截路径所对应的过滤器类型 对应的拦截路径(--!)
public Filter processPathConfig(String path, String config) {
String[] values = null;
if (config != null) {
values = split(config);
}
// 添加过滤链的名称
this.appliedPaths.put(path, values);
return this;
}
小结:
1、在启动后生成 shiroFilter -- SpringShiroFilter 入口过滤器(ShiroFilterFactoryBean类中)
2、在会以拦截规则为key,后面的过滤器生成一条过滤链为 value的形式生成存放在map中(DefaultFilterChainManager类中)
3、会给每个AccessControlFilter类型过滤器设置 登陆、登陆成功、没有认证 的url(ShiroFilterFactoryBean类中)
shiro的DelegatingFilterProxy怎么找到ShiroFilterFactoryBean的更多相关文章
- Shiro的Filter机制详解---源码分析
Shiro的Filter机制详解 首先从spring-shiro.xml的filter配置说起,先回答两个问题: 1, 为什么相同url规则,后面定义的会覆盖前面定义的(执行的时候只执行最后一个). ...
- SSM集成shiro 致使Controller无法自动注册service
由于shiro在web.xml中配置属于过滤器,其中在web.xml中的加载顺序为: <context-param>(上下文) > listener > filter > ...
- Shiro的Filter机制详解---源码分析(转)
Shiro的Filter机制详解 首先从spring-shiro.xml的filter配置说起,先回答两个问题: 1, 为什么相同url规则,后面定义的会覆盖前面定义的(执行的时候只执行最后一个). ...
- Shiro入门之一 -------- Shiro权限认证与授权
一 将Shirojar包导入web项目 二 在web.xml中配置shiro代理过滤器 注意: 该过滤器需要配置在struts2过滤器之前 <!-- 配置Shiro的代理过滤器 --> ...
- 补习系列(6)- springboot 整合 shiro 一指禅
目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...
- SpringBoot集成Shiro 实现动态加载权限
一.前言 本文小编将基于 SpringBoot 集成 Shiro 实现动态uri权限,由前端vue在页面配置uri,Java后端动态刷新权限,不用重启项目,以及在页面分配给用户 角色 . 按钮 .ur ...
- SpringBoot 整合Shiro 一指禅
目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...
- Shiro权限管理框架(五):自定义Filter实现及其问题排查记录
明确需求 在使用Shiro的时候,鉴权失败一般都是返回一个错误页或者登录页给前端,特别是后台系统,这种模式用的特别多.但是现在的项目越来越多的趋向于使用前后端分离的方式开发,这时候就需要响应Json数 ...
- 解决springboot 配置文件未映射静态资源文件 导致shiro拦截静态资源的问题
---------------------------------------------------------------------------------------------------- ...
随机推荐
- Masonry 抗压缩 抗拉伸
约束优先级: 在Autolayout中每个约束都有一个优先级, 优先级的范围是1 ~ 1000.创建一个约束,默认的优先级是最高的1000 Content Hugging Priority: 该优先级 ...
- Linux系统根目录各文件夹的含义
centos7文件结构截图如下: 首先,我要说明我在安装centos系统的过程中,勾选了GNOME的图形界面,功能当中勾选了办公工具和开发工具,办公工具就是类似于微软的office,现在在微软offi ...
- MySql中innodb存储引擎事务日志详解
分析下MySql中innodb存储引擎是如何通过日志来实现事务的? Mysql会最大程度的使用缓存机制来提高数据库的访问效率,但是万一数据库发生断电,因为缓存的数据没有写入磁盘,导致缓存在内存中的数据 ...
- Java公开课-04.异常
一,异常的概念 程序在运行时,发生了我们没有预测的结果,它阻止了程序按照我们预期效果执行 二,怎么保证我们的程序在发生异常以后 ,代码继续执行? 异常处理机制 在程序发生异常以后,还能按照我们事先设定 ...
- Heroku创始人Adam Wiggins发布十二要素应用宣言
Heroku是业内知名的云应用平台,从对外提供服务以来,他们已经有上百万应用的托管和运营经验.前不久,创始人Adam Wiggins根据这些经验,发布了一个“十二要素应用宣言(The Twelve-F ...
- 你不知道的JavaScript--Item1 严格模式
本文转自[阮一峰博客]:http://www.ruanyifeng.com/blog/2013/01/javascript_strict_mode.html 一.概述 除了正常运行模式,ECMAscr ...
- Android 自定义控件实现刮刮卡效果 真的就只是刮刮卡么
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40162163 , 本文出自:[张鸿洋的博客] 很久以前也过一个html5的刮刮卡 ...
- JDBC连接MySQL数据库基础
主要内容 MySQL的基本操作和基本SQL语法 使用JDBC进行MySQL数据库的开发 使用DriverManager.Connection.PreparedStatement.ResultSet对数 ...
- 自动化测试用例getText()获取某一个元素的值返回null或空
问题描述 页面上一个元素无法获取它的值. 用getText() 获取该元素的值返回null或空. 根本原因 ? 需要更多了解dom结构 解决办法 用getAttribute("value&q ...
- selenium相关技术研究(从1.0-3.0)
注: 以下内容引自http://www.cnblogs.com/hhudaqiang/p/6550135.html Selenium相关技术研究(从1.0-3.0) 好吧,最近看wxpython有点多 ...