SpringMVC - Rol DelegatingFilterProxy con el ambiente de uso SpringBoot (shiro [resuelto] al configurar filtros, ¿por qué debería configurar el proxy?)

https://www.cnblogs.com/zhanhaitao/p/7857245.html

La intención original

DelegatingFilterProxy Es un proxy para el filtro de servlet

  • Los beneficios de usar esta clase es principalmente a través del recipiente de primavera para gestionar el ciclo de vida de filtro de servlet
  • Si hay algunos casos en el recipiente de filtro de la primavera se desea, mediante resorte inyección directa
  • También leen algunos archivos de configuración facilitan estas operaciones se pueden configurar en la primavera de poner en práctica

DelegatingFilterProxyExistencia de spring-webpaquete, que es un papelfilter的代理

Indirectamente implementa la interfaz del filtro, pero de hecho invocado en doFilter se retiren del recipiente de primavera al delegado de clase de implementación de agente de filtro.

Aquí Insertar imagen Descripción

No podemos ver en el gráfico, DelegatingFilterProxyla herencia de clases GenericFilterBean, de manera indirecta implementa esta interfaz filtro, y por lo tanto pertenecen a un filtro de clase.

A continuación, se habrían dado cuenta del inicio del filtro, doFilter, destruir tres métodos.

realización actuando

# en eso

En primer lugar, nos fijamos en initel método, sabemosCuando el filtro se realice el método de inicialización init

De la fuente se encuentra el código específico, el método se implementa en la clase GenericFilterBean, funciones específicas son:

  • Las clases específicas como formulario basado en la primavera, fácil de mantener primavera
  • Y llamar al método initFilterBean en la subclase (por DelegatingFilterProxy) alcanzado, que propósito principal es encontrar el filtro de destino mantenido en la primavera, para ver plasmado en el siguiente código:
	/**
	 * Standard way of initializing this filter.
	 * Map config parameters onto bean properties of this filter, and
	 * invoke subclass initialization.
	 * @param filterConfig the configuration for this filter
	 * @throws ServletException if bean properties are invalid (or required
	 * properties are missing), or if subclass initialization fails.
	 * @see #initFilterBean
	 */
	@Override
	public final void init(FilterConfig filterConfig) throws ServletException {
		Assert.notNull(filterConfig, "FilterConfig must not be null");

		this.filterConfig = filterConfig;

		!将该类封装成spring特有的bean形式,方便spring维护
				↓
		// Set bean properties from init parameters.
		PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);
		if (!pvs.isEmpty()) {
			try {
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
				ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());
				Environment env = this.environment;
				if (env == null) {
					env = new StandardServletEnvironment();
				}
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, env));
				initBeanWrapper(bw);
				bw.setPropertyValues(pvs, true);
			}
			catch (BeansException ex) {
				String msg = "Failed to set bean properties on filter '" +
					filterConfig.getFilterName() + "': " + ex.getMessage();
				logger.error(msg, ex);
				throw new NestedServletException(msg, ex);
			}
		}
		
		!该方法 initFilterBean 在子类 (DelegatingFilterProxy) 中实现
		我们可以到DelegatingFilterPoxy中去看看,具体完成了那些工作?
	  1、找到要代理bean的id ==> targetBeanName
	  2、在spring,bean容器中找到具体被代理的filter ==> delegate
			↓
		// Let subclasses do whatever initialization they like.
		initFilterBean();

		if (logger.isDebugEnabled()) {
			logger.debug("Filter '" + filterConfig.getFilterName() + "' configured for use");
		}
	}

initFilterBean() Este método realiza dos funciones principales :( código a continuación)

  1. Encuentra clase proxy está configurado en la primavera idy se asigna a targetBeanName.
  2. Uso encontró idde springproxy específica clase de contenedor encontrado, y se asigna adelegate
@Override
protected void initFilterBean() throws ServletException {
	synchronized (this.delegateMonitor) {
		if (this.delegate == null) {
			// If no target bean name specified, use filter name.
			if (this.targetBeanName == null) {
			
				!找到要被代理的filter在spring中配置的id(name)this.targetBeanName = getFilterName();
			}
			// Fetch Spring root application context and initialize the delegate early,
			// if possible. If the root application context will be started after this
			// filter proxy, we'll have to resort to lazy initialization.
			WebApplicationContext wac = findWebApplicationContext();
			if (wac != null) {

				!找到具体被代理的filter
					↓
				this.delegate = initDelegate(wac);
			}
		}
	}
}

getFilterName()El efecto del método es adquirida por el agente filterdispuesto en la primavera id(continuación)

	/**
	 * Make the name of this filter available to subclasses.
	 * Analogous to GenericServlet's {@code getServletName()}.
	 * <p>Takes the FilterConfig's filter name by default.
	 * If initialized as bean in a Spring application context,
	 * it falls back to the bean name as defined in the bean factory.
	 * @return the filter name, or {@code null} if none available
	 * @see javax.servlet.GenericServlet#getServletName()
	 * @see javax.servlet.FilterConfig#getFilterName()
	 * @see #setBeanName
	 */
	@Nullable
	protected String getFilterName() {
	
		!找到被代理filter在spring中配置的id
			↓
		return (this.filterConfig != null ? this.filterConfig.getFilterName() : this.beanName);
	}

initDelegate() Efecto de este método se adquiere desde el recipiente hasta la primavera en particular proxy filter

	/**
	 * Initialize the Filter delegate, defined as bean the given Spring
	 * application context.
	 * <p>The default implementation fetches the bean from the application context
	 * and calls the standard {@code Filter.init} method on it, passing
	 * in the FilterConfig of this Filter proxy.
	 * @param wac the root application context
	 * @return the initialized delegate Filter
	 * @throws ServletException if thrown by the Filter
	 * @see #getTargetBeanName()
	 * @see #isTargetFilterLifecycle()
	 * @see #getFilterConfig()
	 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
	 */
	protected Filter initDelegate(WebApplicationContext wac) throws ServletException {

		! 取出上面找到的 id
			↓
		String targetBeanName = getTargetBeanName();
		Assert.state(targetBeanName != null, "No target bean name set");
		
		! 找到被代理的filter
			↓
		Filter delegate = wac.getBean(targetBeanName, Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}

Aquí podemos ver, queremos que el agente filter, de hecho, hemos configurado filterla filter-nameetiqueta filterNamede

<filter-name>filterName</filter-name>

# doFilter

Tomamos un vistazo doFilteral método de aplicación específica, que utilizan, sobre todo 被代理的filter, y llamar al invokeDelegatemétodo,
la puesta en práctica 被代理filterdel doFilterprocedimiento, la aplicación específica, consulte el código fuente a continuación:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
		throws ServletException, IOException {

	! 得到被代理的filter
		↓
	// Lazily initialize the delegate if necessary.
	Filter delegateToUse = this.delegate;
	if (delegateToUse == null) {
		synchronized (this.delegateMonitor) {
			delegateToUse = this.delegate;
			if (delegateToUse == null) {
				WebApplicationContext wac = findWebApplicationContext();
				if (wac == null) {
					throw new IllegalStateException("No WebApplicationContext found: " +
							"no ContextLoaderListener or DispatcherServlet registered?");
				}
				delegateToUse = initDelegate(wac);
			}
			this.delegate = delegateToUse;
		}
	}

	! 执行被代理filter的doFilter方法
		↓
	// Let the delegate perform the actual doFilter operation.
	invokeDelegate(delegateToUse, request, response, filterChain);
}

invokeDelegate El método es para llevar a cabo el papel de ser un método de filtro de proxy de doFilter

/**
 * Actually invoke the delegate Filter with the given request and response.
 * @param delegate the delegate Filter
 * @param request the current HTTP request
 * @param response the current HTTP response
 * @param filterChain the current FilterChain
 * @throws ServletException if thrown by the Filter
 * @throws IOException if thrown by the Filter
 */
protected void invokeDelegate(
		Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
		throws ServletException, IOException {

	delegate.doFilter(request, response, filterChain);
}

Vea aquí, creo que todos entendemos DelegatingFilterPoxy cómo es ahora.

Aquí nos fijamos en la primavera + shiro es cómo utilizar esta clase

Uso (medio ambiente SpringBoot)

demanda

En springboot en el filtro, y herramientas de negocio inyectados (APIUtil), pero la inyección es nulo

Así surge la pregunta: ¿Cuándo filtro de frijol springboot inyectar utilizado es la solución nula

Análisis : Primavera De hecho, se puso en marcha el fin de la aplicación web:

⇒ ⇒ oyente filtro de servlet

Es decir, la primera escucha de inicialización, y luego volver a la inicialización del filtro, entonces y sólo entonces a la inicialización de nuestra dispathServlet

razón

pero filtro de servlet se define en la especificación, no devuelve la gestión de contenedores de muelle, no puede ser inyectado directamente en el grano de resorte (siendo dado)

Solución # 1

public class TokenAuthFilter implements Filter {
 
    private final static Logger log = LoggerFactory.getLogger(TokenAuthFilter.class);
 
    @Autowired
    private APIUtil apiUtil;
}

Añadir una clase de configuración, crear un filtro para el grano a mano, por ejemplo:

@Configuration
public class WebConfig {
 
  @Bean
    public Filter tokenAuthFilter() {
 
        return new TokenAuthFilter();
    }
    /**
     * 注册filter,统一处理api开头的请求
     * @return FilterRegistrationBean
     */
    @Bean
    public FilterRegistrationBean tokenAuthFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        // DelegatingFilterProxy把servlet 容器中的filter同spring容器中的bean关联起来
        registration.setFilter(new DelegatingFilterProxy("tokenAuthFilter"));
        registration.addUrlPatterns("/api/*");
        registration.setName("tokenAuthFilter");
        registration.setOrder(1);
        return registration;
    }
 
}

Solución # 2 (alto acoplamiento)

Adquirida por la inicialización del contexto de la primavera, la inicialización para el bean:

@Override
public void init(FilterConfig filterConfig) throws ServletException {
    ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
    RedisTemplate demoBean = (RedisTemplate)context.getBean("redisTemplate");
    System.out.println(demoBean);
 }
Publicados 501 artículos originales · ganado elogios 112 · Vistas a 20000 +

Supongo que te gusta

Origin blog.csdn.net/LawssssCat/article/details/105027791
Recomendado
Clasificación