首先看到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的更多相关文章

  1. Shiro的Filter机制详解---源码分析

    Shiro的Filter机制详解 首先从spring-shiro.xml的filter配置说起,先回答两个问题: 1, 为什么相同url规则,后面定义的会覆盖前面定义的(执行的时候只执行最后一个). ...

  2. SSM集成shiro 致使Controller无法自动注册service

    由于shiro在web.xml中配置属于过滤器,其中在web.xml中的加载顺序为: <context-param>(上下文) > listener > filter > ...

  3. Shiro的Filter机制详解---源码分析(转)

    Shiro的Filter机制详解 首先从spring-shiro.xml的filter配置说起,先回答两个问题: 1, 为什么相同url规则,后面定义的会覆盖前面定义的(执行的时候只执行最后一个). ...

  4. Shiro入门之一 -------- Shiro权限认证与授权

    一  将Shirojar包导入web项目 二 在web.xml中配置shiro代理过滤器 注意: 该过滤器需要配置在struts2过滤器之前 <!-- 配置Shiro的代理过滤器 -->  ...

  5. 补习系列(6)- springboot 整合 shiro 一指禅

    目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...

  6. SpringBoot集成Shiro 实现动态加载权限

    一.前言 本文小编将基于 SpringBoot 集成 Shiro 实现动态uri权限,由前端vue在页面配置uri,Java后端动态刷新权限,不用重启项目,以及在页面分配给用户 角色 . 按钮 .ur ...

  7. SpringBoot 整合Shiro 一指禅

    目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...

  8. Shiro权限管理框架(五):自定义Filter实现及其问题排查记录

    明确需求 在使用Shiro的时候,鉴权失败一般都是返回一个错误页或者登录页给前端,特别是后台系统,这种模式用的特别多.但是现在的项目越来越多的趋向于使用前后端分离的方式开发,这时候就需要响应Json数 ...

  9. 解决springboot 配置文件未映射静态资源文件 导致shiro拦截静态资源的问题

    ---------------------------------------------------------------------------------------------------- ...

随机推荐

  1. C# DataGridView绑定List对象时,利用BindingList来实现增删查改

    当DataGridView的DataSource是DataTable的时候,DataTable的数据改变时,DataGridView的数据会随之改变,无需重新绑定到DataGridView.  当Da ...

  2. sql优化总结

    在项目前期目标是确保功能能够正常运行,但是随着时间的推移,数据的增加,逻辑的复杂,导致数据查询会越来越慢,这个时候我们首先想到的应该就是尽量优化sql. sql优化常见注意点: 1.对查询进行优化,应 ...

  3. Java NIO SocketChannel套接字通道

    原文链接:http://tutorials.jenkov.com/java-nio/socketchannel.html 在Java NIO体系中,SocketChannel是用于TCP网络连接的套接 ...

  4. SSM-MyBatis-06:Mybatis中openSession到底做了什么

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 1.找SqlSesionFactory实现类 Ctrl+H:DefaultSqlSessionFactory: ...

  5. 好代码是管出来的——使用Git来管理源代码

    软件开发过程中一个重要的产出就是代码,软件的编码过程一般是由一个团队共同完成,它是一个并行活动,为了保证代码在多人开发中能够顺利完成,我们需要使用代码版本控制工具来对代码进行统一存储,并追踪每一份代码 ...

  6. CAPTCHA---验证码 ---Security code

    BotDetect Java CAPTCHA Generator 3. Add BotDetect Java CAPTCHA Library Dependency Here is how to add ...

  7. Step by step guide to set up master and slave machines on Windows

    Note: There is no need to install Jenkins on the slave machine. On your master machine go to Manage ...

  8. [ Java面试题 ]数据库篇

    基本表结构: student(sno,sname,sage,ssex)学生表 course(cno,cname,tno) 课程表 sc(sno,cno,score) 成绩表 teacher(tno,t ...

  9. SpringBoot如何新建一个项目 2017.12.14

    http://blog.csdn.net/q649381130/article/details/77875736  从入门到精通

  10. 如何将数据库中存的树转化为树形列表(以easyui的tree为例)

    很多时候,我们会把一棵树存放到数据库中,当前台需要展示一个树形列表时,将这棵树读取出来并显示,这个过程是怎么实现的呢? 这篇文章是以构造一棵easyui前台框架的一个树形列表为例,后台框架是sprin ...