【Spring实战】----源码解析Spring Security4.1.3中的过滤器Filter配置

123 篇文章 0 订阅
27 篇文章 3 订阅

Spring Security的底层是通过一系列的Filter来管理的,每个Filter都有其自身的功能,那么这些Filter是怎么配置到系统中的?

一、web.xml配置

通常web使用会在web.xml中进行如下配置

<!-- Spring-security -->
	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>
			org.springframework.web.filter.DelegatingFilterProxy
		</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

而DelegatingFilterProxy并不是真正工作的Filter,org.springframework.web.filter.DelegatingFilterProxy.java

@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) {
					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) {
					this.delegate = initDelegate(wac);
				}
			}
		}
	}


会从WebApplicationContext中得到delegate,而真正的工作有delegate来实现

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

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

		// Let the delegate perform the actual doFilter operation.
		invokeDelegate(delegateToUse, request, response, filterChain);
	}

而这个delegate是FilterChainProxy,从代码中可以看出这个FilterChainProxy是Spring在解析配置文件时装配到上下文中的,并且beanName为"springSecurityFilterChain",因此在web.xml中需要配置filter-name为springSecurityFilterChain,否则就不能获取到FilterChainProxy。最终这个代理还是把工作交给了FilterList来处理,其中保存的就是Security系统中的一系列Filter。那么这些Filter也是在解析配置文件的时候注册到上下文中的。下面具体看下Security配置文件的解析,主要是<http>标签

二、<http>标签的解析

在配置文件中需要配置<http>才能使用Security,

<http auto-config="true" use-expressions="true" >
		<form-login 
			login-page="/login"
            authentication-failure-url="/login?error" 
            login-processing-url="/login"
            authentication-success-handler-ref="myAuthenticationSuccessHandler" />   
         <!-- 认证成功用自定义类myAuthenticationSuccessHandler处理 -->
         
         <logout logout-url="/logout" 
				logout-success-url="/" 
				invalidate-session="true"
				delete-cookies="JSESSIONID"/>
		<!-- 禁用csrf功能 -->
		<csrf disabled="true" />
		<intercept-url pattern="/order/*" access="hasRole('ROLE_USER')"/>
	</http>

接下来看下,解析该标签时做了什么?该标签是自定义标签,查看spring.handlers(在spring-security-config包中)

http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler


SecurityNamespaceHandler.java

parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());


由HttpSecurityBeanDefinitionParser解析器解析

/**
	 * The aim of this method is to build the list of filters which have been defined by
	 * the namespace elements and attributes within the <http> configuration, along
	 * with any custom-filter's linked to user-defined filter beans.
	 * <p>
	 * By the end of this method, the default <tt>FilterChainProxy</tt> bean should have
	 * been registered and will have the map of filter chains defined, with the
	 * "universal" match pattern mapped to the list of beans which have been parsed here.
	 */
	@SuppressWarnings({ "unchecked" })
	public BeanDefinition parse(Element element, ParserContext pc) {
		CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(
				element.getTagName(), pc.extractSource(element));
		pc.pushContainingComponent(compositeDef);

		registerFilterChainProxyIfNecessary(pc, pc.extractSource(element));    //Filter注册

		// Obtain the filter chains and add the new chain to it
		BeanDefinition listFactoryBean = pc.getRegistry().getBeanDefinition(
				BeanIds.FILTER_CHAINS);
		List<BeanReference> filterChains = (List<BeanReference>) listFactoryBean
				.getPropertyValues().getPropertyValue("sourceList").getValue();

		filterChains.add(createFilterChain(element, pc));                   //一系列Filter的注册

		pc.popAndRegisterContainingComponent();
		return null;
	}

先看registerFilterChainProxyIfNecessary

static void registerFilterChainProxyIfNecessary(ParserContext pc, Object source) {
		if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
			return;
		}
		// Not already registered, so register the list of filter chains and the
		// FilterChainProxy
		BeanDefinition listFactoryBean = new RootBeanDefinition(ListFactoryBean.class);
		listFactoryBean.getPropertyValues().add("sourceList", new ManagedList());
		pc.registerBeanComponent(new BeanComponentDefinition(listFactoryBean,
				BeanIds.FILTER_CHAINS));

		BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder
				.rootBeanDefinition(FilterChainProxy.class);
		fcpBldr.getRawBeanDefinition().setSource(source);
		fcpBldr.addConstructorArgReference(BeanIds.FILTER_CHAINS);
		fcpBldr.addPropertyValue("filterChainValidator", new RootBeanDefinition(
				DefaultFilterChainValidator.class));
		BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
		pc.registerBeanComponent(new BeanComponentDefinition(fcpBean,
				BeanIds.FILTER_CHAIN_PROXY));
		pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY,
				BeanIds.SPRING_SECURITY_FILTER_CHAIN);             //springSecurityFilterChain
	}

其他的先不管,直接看最后,常量为,这里就是注册了名为springSecurityFilterChain的filterChainProxy类

private static final String PREFIX = "org.springframework.security.";

/** External alias for FilterChainProxy bean, for use in web.xml files */
	public static final String SPRING_SECURITY_FILTER_CHAIN = "springSecurityFilterChain";

public static final String FILTER_CHAIN_PROXY = PREFIX + "filterChainProxy";



看下注册一系列Filter的地方createFilterChain

/**
	 * Creates the {@code SecurityFilterChain} bean from an <http> element.
	 */
	private BeanReference createFilterChain(Element element, ParserContext pc) {
		boolean secured = !OPT_SECURITY_NONE.equals(element.getAttribute(ATT_SECURED));

		if (!secured) {
			if (!StringUtils.hasText(element.getAttribute(ATT_PATH_PATTERN))
					&& !StringUtils.hasText(ATT_REQUEST_MATCHER_REF)) {
				pc.getReaderContext().error(
						"The '" + ATT_SECURED
								+ "' attribute must be used in combination with"
								+ " the '" + ATT_PATH_PATTERN + "' or '"
								+ ATT_REQUEST_MATCHER_REF + "' attributes.",
						pc.extractSource(element));
			}

			for (int n = 0; n < element.getChildNodes().getLength(); n++) {
				if (element.getChildNodes().item(n) instanceof Element) {
					pc.getReaderContext().error(
							"If you are using <http> to define an unsecured pattern, "
									+ "it cannot contain child elements.",
							pc.extractSource(element));
				}
			}

			return createSecurityFilterChainBean(element, pc, Collections.emptyList());
		}

		final BeanReference portMapper = createPortMapper(element, pc);
		final BeanReference portResolver = createPortResolver(portMapper, pc);

		ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
		BeanReference authenticationManager = createAuthenticationManager(element, pc,
				authenticationProviders);

		boolean forceAutoConfig = isDefaultHttpConfig(element);
		HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element,
				forceAutoConfig, pc, portMapper, portResolver, authenticationManager);

		AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element,
				forceAutoConfig, pc, httpBldr.getSessionCreationPolicy(),
				httpBldr.getRequestCache(), authenticationManager,
				httpBldr.getSessionStrategy(), portMapper, portResolver,
				httpBldr.getCsrfLogoutHandler());

		httpBldr.setLogoutHandlers(authBldr.getLogoutHandlers());
		httpBldr.setEntryPoint(authBldr.getEntryPointBean());
		httpBldr.setAccessDeniedHandler(authBldr.getAccessDeniedHandlerBean());

		authenticationProviders.addAll(authBldr.getProviders());

		List<OrderDecorator> unorderedFilterChain = new ArrayList<OrderDecorator>();

		unorderedFilterChain.addAll(httpBldr.getFilters());                       //this
		unorderedFilterChain.addAll(authBldr.getFilters());
		unorderedFilterChain.addAll(buildCustomFilterList(element, pc));

		Collections.sort(unorderedFilterChain, new OrderComparator());
		checkFilterChainOrder(unorderedFilterChain, pc, pc.extractSource(element));

		// The list of filter beans
		List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>();

		for (OrderDecorator od : unorderedFilterChain) {
			filterChain.add(od.bean);
		}

		return createSecurityFilterChainBean(element, pc, filterChain);
	}

HttpConfigurationBuilder配置中会创建

public HttpConfigurationBuilder(Element element, boolean addAllAuth,
			ParserContext pc, BeanReference portMapper, BeanReference portResolver,
			BeanReference authenticationManager) {
		this.httpElt = element;
		this.addAllAuth = addAllAuth;
		this.pc = pc;
		this.portMapper = portMapper;
		this.portResolver = portResolver;
		this.matcherType = MatcherType.fromElement(element);
		interceptUrls = DomUtils.getChildElementsByTagName(element,
				Elements.INTERCEPT_URL);

		for (Element urlElt : interceptUrls) {
			if (StringUtils.hasText(urlElt.getAttribute(ATT_FILTERS))) {
				pc.getReaderContext()
						.error("The use of \"filters='none'\" is no longer supported. Please define a"
								+ " separate <http> element for the pattern you want to exclude and use the attribute"
								+ " \"security='none'\".", pc.extractSource(urlElt));
			}
		}

		String createSession = element.getAttribute(ATT_CREATE_SESSION);

		if (StringUtils.hasText(createSession)) {
			sessionPolicy = createPolicy(createSession);
		}
		else {
			sessionPolicy = SessionCreationPolicy.IF_REQUIRED;
		}

		createCsrfFilter();                                    //this
		createSecurityContextPersistenceFilter();
		createSessionManagementFilters();
		createWebAsyncManagerFilter();
		createRequestCacheFilter();
		createServletApiFilter(authenticationManager);
		createJaasApiFilter();
		createChannelProcessingFilter();
		createFilterSecurityInterceptor(authenticationManager);
		createAddHeadersFilter();
		createCorsFilter();
	}


AuthenticationConfigBuilder也会创建

public AuthenticationConfigBuilder(Element element, boolean forceAutoConfig,
			ParserContext pc, SessionCreationPolicy sessionPolicy,
			BeanReference requestCache, BeanReference authenticationManager,
			BeanReference sessionStrategy, BeanReference portMapper,
			BeanReference portResolver, BeanMetadataElement csrfLogoutHandler) {
		this.httpElt = element;
		this.pc = pc;
		this.requestCache = requestCache;
		autoConfig = forceAutoConfig
				| "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
		this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.NEVER
				&& sessionPolicy != SessionCreationPolicy.STATELESS;
		this.portMapper = portMapper;
		this.portResolver = portResolver;
		this.csrfLogoutHandler = csrfLogoutHandler;

		createAnonymousFilter();
		createRememberMeFilter(authenticationManager);
		createBasicFilter(authenticationManager);
		createFormLoginFilter(sessionStrategy, authenticationManager);
		createOpenIDLoginFilter(sessionStrategy, authenticationManager);
		createX509Filter(authenticationManager);
		createJeeFilter(authenticationManager);
		createLogoutFilter();
		createLoginPageFilterIfNeeded();
		createUserDetailsServiceFactory();
		createExceptionTranslationFilter();

	}

单看一个createFormLoginFilter,就是针对标签<form-login>的配置解析,其实创建的是UsernamePasswordAuthenticationFilter

static final String AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter";

void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {

		Element formLoginElt = DomUtils.getChildElementByTagName(httpElt,
				Elements.FORM_LOGIN);
		RootBeanDefinition formFilter = null;

		if (formLoginElt != null || autoConfig) {
			FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser(
					"/login", "POST", AUTHENTICATION_PROCESSING_FILTER_CLASS,
					requestCache, sessionStrategy, allowSessionCreation, portMapper,
					portResolver);

			parser.parse(formLoginElt, pc);
			formFilter = parser.getFilterBean();
			formEntryPoint = parser.getEntryPointBean();
			loginProcessingUrl = parser.getLoginProcessingUrl();
			formLoginPage = parser.getLoginPage();
		}

		if (formFilter != null) {
			formFilter.getPropertyValues().addPropertyValue("allowSessionCreation",
					allowSessionCreation);
			formFilter.getPropertyValues().addPropertyValue("authenticationManager",
					authManager);

			// Id is required by login page filter
			formFilterId = pc.getReaderContext().generateBeanName(formFilter);
			pc.registerBeanComponent(new BeanComponentDefinition(formFilter, formFilterId));
			injectRememberMeServicesRef(formFilter, rememberMeServicesId);
		}
	}

又交给解析器FormLoginBeanDefinitionParser,其parse方法也很长,单说上一篇中配置的authentication-success-handler-ref="myAuthenticationSuccessHandler"的作用。

public BeanDefinition parse(Element elt, ParserContext pc) {
......
		String successHandlerRef = null;
.......//private static final String ATT_SUCCESS_HANDLER_REF = "authentication-success-handler-ref";
	        successHandlerRef = elt.getAttribute(ATT_SUCCESS_HANDLER_REF);
              filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault,
				loginPage, authenticationFailureUrl, successHandlerRef,
				failureHandlerRef, authDetailsSourceRef, authenticationFailureForwardUrl, authenticationSuccessForwardUrl);

		.......	}

在createFilterBean中单看successHandlerRef的处理,如果配置了则使用配置的successHandler,优先使用authentication-success-handler-ref属性配置的,其次使用authentication-success-forward-url属性配置的,否则使用默认的SavedRequestAwareAuthenticationSuccessHandler

if (StringUtils.hasText(successHandlerRef)) {
			filterBuilder.addPropertyReference("authenticationSuccessHandler",
					successHandlerRef);
		} else if(StringUtils.hasText(authenticationSuccessForwardUrl)) {
			BeanDefinitionBuilder forwardSuccessHandler = BeanDefinitionBuilder
					.rootBeanDefinition(ForwardAuthenticationSuccessHandler.class);
			forwardSuccessHandler.addConstructorArgValue(authenticationSuccessForwardUrl);
			filterBuilder.addPropertyValue("authenticationSuccessHandler", forwardSuccessHandler.getBeanDefinition());
		} else {
			BeanDefinitionBuilder successHandler = BeanDefinitionBuilder
					.rootBeanDefinition(SavedRequestAwareAuthenticationSuccessHandler.class);
			if ("true".equals(alwaysUseDefault)) {
				successHandler
						.addPropertyValue("alwaysUseDefaultTargetUrl", Boolean.TRUE);
			}
			successHandler.addPropertyValue("requestCache", requestCache);
			successHandler.addPropertyValue("defaultTargetUrl", StringUtils
					.hasText(defaultTargetUrl) ? defaultTargetUrl
					: DEF_FORM_LOGIN_TARGET_URL);
			filterBuilder.addPropertyValue("authenticationSuccessHandler",
					successHandler.getBeanDefinition());
		}
这里就说明了4.1.3后会将待认证的请求信息保存,认证完成后再恢复。

并且这些Filter会根据枚举类SecurityFilters进行排序

enum SecurityFilters {
	FIRST(Integer.MIN_VALUE), CHANNEL_FILTER, SECURITY_CONTEXT_FILTER, CONCURRENT_SESSION_FILTER,
	/** {@link WebAsyncManagerIntegrationFilter} */
	WEB_ASYNC_MANAGER_FILTER, HEADERS_FILTER, CORS_FILTER, CSRF_FILTER, LOGOUT_FILTER, X509_FILTER, PRE_AUTH_FILTER, CAS_FILTER, FORM_LOGIN_FILTER, OPENID_FILTER, LOGIN_PAGE_FILTER, DIGEST_AUTH_FILTER, BASIC_AUTH_FILTER, REQUEST_CACHE_FILTER, SERVLET_API_SUPPORT_FILTER, JAAS_API_SUPPORT_FILTER, REMEMBER_ME_FILTER, ANONYMOUS_FILTER, SESSION_MANAGEMENT_FILTER, EXCEPTION_TRANSLATION_FILTER, FILTER_SECURITY_INTERCEPTOR, SWITCH_USER_FILTER, LAST(
			Integer.MAX_VALUE);

	private static final int INTERVAL = 100;
	private final int order;

	private SecurityFilters() {
		order = ordinal() * INTERVAL;
	}

	private SecurityFilters(int order) {
		this.order = order;
	}

	public int getOrder() {
		return order;
	}
}

根据上述的枚举类就可看出各个Filter的顺序。

三、Filter的排序方法

采用的是实现java.util.Comparator接口,利用现有api  Collections.sort实现排序

Collections.sort(unorderedFilterChain, new OrderComparator());

public class OrderComparator implements Comparator<Object> {

	/**
	 * Shared default instance of {@code OrderComparator}.
	 */
	public static final OrderComparator INSTANCE = new OrderComparator();


	/**
	 * Build an adapted order comparator with the given source provider.
	 * @param sourceProvider the order source provider to use
	 * @return the adapted comparator
	 * @since 4.1
	 */
	public Comparator<Object> withSourceProvider(final OrderSourceProvider sourceProvider) {
		return new Comparator<Object>() {
			@Override
			public int compare(Object o1, Object o2) {
				return doCompare(o1, o2, sourceProvider);
			}
		};
	}

	@Override
	public int compare(Object o1, Object o2) {
		return doCompare(o1, o2, null);
	}

	private int doCompare(Object o1, Object o2, OrderSourceProvider sourceProvider) {
		boolean p1 = (o1 instanceof PriorityOrdered);
		boolean p2 = (o2 instanceof PriorityOrdered);
		if (p1 && !p2) {
			return -1;
		}
		else if (p2 && !p1) {
			return 1;
		}

		// Direct evaluation instead of Integer.compareTo to avoid unnecessary object creation.
		int i1 = getOrder(o1, sourceProvider);
		int i2 = getOrder(o2, sourceProvider);
		return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
	}

	/**
	 * Determine the order value for the given object.
	 * <p>The default implementation checks against the given {@link OrderSourceProvider}
	 * using {@link #findOrder} and falls back to a regular {@link #getOrder(Object)} call.
	 * @param obj the object to check
	 * @return the order value, or {@code Ordered.LOWEST_PRECEDENCE} as fallback
	 */
	private int getOrder(Object obj, OrderSourceProvider sourceProvider) {
		Integer order = null;
		if (sourceProvider != null) {
			Object orderSource = sourceProvider.getOrderSource(obj);
			if (orderSource != null && orderSource.getClass().isArray()) {
				Object[] sources = ObjectUtils.toObjectArray(orderSource);
				for (Object source : sources) {
					order = findOrder(source);
					if (order != null) {
						break;
					}
				}
			}
			else {
				order = findOrder(orderSource);
			}
		}
		return (order != null ? order : getOrder(obj));
	}

	/**
	 * Determine the order value for the given object.
	 * <p>The default implementation checks against the {@link Ordered} interface
	 * through delegating to {@link #findOrder}. Can be overridden in subclasses.
	 * @param obj the object to check
	 * @return the order value, or {@code Ordered.LOWEST_PRECEDENCE} as fallback
	 */
	protected int getOrder(Object obj) {
		Integer order = findOrder(obj);
		return (order != null ? order : Ordered.LOWEST_PRECEDENCE);
	}

	/**
	 * Find an order value indicated by the given object.
	 * <p>The default implementation checks against the {@link Ordered} interface.
	 * Can be overridden in subclasses.
	 * @param obj the object to check
	 * @return the order value, or {@code null} if none found
	 */
	protected Integer findOrder(Object obj) {
		return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null);
	}

	/**
	 * Determine a priority value for the given object, if any.
	 * <p>The default implementation always returns {@code null}.
	 * Subclasses may override this to give specific kinds of values a
	 * 'priority' characteristic, in addition to their 'order' semantics.
	 * A priority indicates that it may be used for selecting one object over
	 * another, in addition to serving for ordering purposes in a list/array.
	 * @param obj the object to check
	 * @return the priority value, or {@code null} if none
	 * @since 4.1
	 */
	public Integer getPriority(Object obj) {
		return null;
	}


	/**
	 * Sort the given List with a default OrderComparator.
	 * <p>Optimized to skip sorting for lists with size 0 or 1,
	 * in order to avoid unnecessary array extraction.
	 * @param list the List to sort
	 * @see java.util.Collections#sort(java.util.List, java.util.Comparator)
	 */
	public static void sort(List<?> list) {
		if (list.size() > 1) {
			Collections.sort(list, INSTANCE);
		}
	}

	/**
	 * Sort the given array with a default OrderComparator.
	 * <p>Optimized to skip sorting for lists with size 0 or 1,
	 * in order to avoid unnecessary array extraction.
	 * @param array the array to sort
	 * @see java.util.Arrays#sort(Object[], java.util.Comparator)
	 */
	public static void sort(Object[] array) {
		if (array.length > 1) {
			Arrays.sort(array, INSTANCE);
		}
	}

	/**
	 * Sort the given array or List with a default OrderComparator,
	 * if necessary. Simply skips sorting when given any other value.
	 * <p>Optimized to skip sorting for lists with size 0 or 1,
	 * in order to avoid unnecessary array extraction.
	 * @param value the array or List to sort
	 * @see java.util.Arrays#sort(Object[], java.util.Comparator)
	 */
	public static void sortIfNecessary(Object value) {
		if (value instanceof Object[]) {
			sort((Object[]) value);
		}
		else if (value instanceof List) {
			sort((List<?>) value);
		}
	}


	/**
	 * Strategy interface to provide an order source for a given object.
	 * @since 4.1
	 */
	public interface OrderSourceProvider {

		/**
		 * Return an order source for the specified object, i.e. an object that
		 * should be checked for an order value as a replacement to the given object.
		 * <p>Can also be an array of order source objects.
		 * <p>If the returned object does not indicate any order, the comparator
		 * will fall back to checking the original object.
		 * @param obj the object to find an order source for
		 * @return the order source for that object, or {@code null} if none found
		 */
		Object getOrderSource(Object obj);
	}

}

sort实现

/**
     * Sorts the specified list according to the order induced by the
     * specified comparator.  All elements in the list must be <i>mutually
     * comparable</i> using the specified comparator (that is,
     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
     * for any elements {@code e1} and {@code e2} in the list).
     *
     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
     * not be reordered as a result of the sort.
     *
     * <p>The specified list must be modifiable, but need not be resizable.
     *
     * @implNote
     * This implementation defers to the {@link List#sort(Comparator)}
     * method using the specified list and comparator.
     *
     * @param  <T> the class of the objects in the list
     * @param  list the list to be sorted.
     * @param  c the comparator to determine the order of the list.  A
     *        {@code null} value indicates that the elements' <i>natural
     *        ordering</i> should be used.
     * @throws ClassCastException if the list contains elements that are not
     *         <i>mutually comparable</i> using the specified comparator.
     * @throws UnsupportedOperationException if the specified list's
     *         list-iterator does not support the {@code set} operation.
     * @throws IllegalArgumentException (optional) if the comparator is
     *         found to violate the {@link Comparator} contract
     * @see List#sort(Comparator)
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }

还有一种方法实现序列比较,就是参与比较类实现Comparable接口,利用Collections如下sort方法

 /**
     * Sorts the specified list into ascending order, according to the
     * {@linkplain Comparable natural ordering} of its elements.
     * All elements in the list must implement the {@link Comparable}
     * interface.  Furthermore, all elements in the list must be
     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)}
     * must not throw a {@code ClassCastException} for any elements
     * {@code e1} and {@code e2} in the list).
     *
     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
     * not be reordered as a result of the sort.
     *
     * <p>The specified list must be modifiable, but need not be resizable.
     *
     * @implNote
     * This implementation defers to the {@link List#sort(Comparator)}
     * method using the specified list and a {@code null} comparator.
     *
     * @param  <T> the class of the objects in the list
     * @param  list the list to be sorted.
     * @throws ClassCastException if the list contains elements that are not
     *         <i>mutually comparable</i> (for example, strings and integers).
     * @throws UnsupportedOperationException if the specified list's
     *         list-iterator does not support the {@code set} operation.
     * @throws IllegalArgumentException (optional) if the implementation
     *         detects that the natural ordering of the list elements is
     *         found to violate the {@link Comparable} contract
     * @see List#sort(Comparator)
     */
    @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }



当然数组类Arrays也有类似的方法。


总结:

security是基于过滤器的,过滤器的配置都是在配置文件解析时做的。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值