【走近Spring】Spring标准处理组件大合集(ParameterNameDiscoverer、AutowireCandidateResolver、ResolvableType...)
在阅读Spring源码的时候,经常会遇见一些处理器、提供器之类的组件,有的时候不深入去理解它的含义,确实还读不下去了。
为了方便自己流畅的阅读下去,本文介绍Spring提供的处理组件,尽量的解释清楚它们的作用甚至原理,以便我们能更自由的阅读。
ParameterNameDiscoverer:获取方法参数名称的工具
DefaultParameterNameDiscoverer:它其实就是个聚合的作用
// Spring4.0后出现的类(伴随着StandardReflectionParameterNameDiscoverer一起出现的)
public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer {
private static final boolean kotlinPresent =
ClassUtils.isPresent("kotlin.Unit", DefaultParameterNameDiscoverer.class.getClassLoader());
public DefaultParameterNameDiscoverer() {
// 这里非常非常需要注意的一点是:用于存储的是一个LinkedList(见父类:PrioritizedParameterNameDiscoverer)
// LinkedList是先进先出的。所以for循环遍历的时候,会最先执行Kotlin、Standard、Local... 按照这个优先级
if (kotlinPresent) {
addDiscoverer(new KotlinReflectionParameterNameDiscoverer());
}
addDiscoverer(new StandardReflectionParameterNameDiscoverer());
addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
}
}
这里面就是给注册进去了实际意义上干事情的三个ParameterNameDiscoverer。然后它自己的方法getParameterNames和getParameterNames都由注册进来的去完成~~~~~~~方法都在它的父类:
PrioritizedParameterNameDiscoverer
// Spring2.0就出现了。它的一个原则很简单:这么多发现器,按照顺序执行,随获取到了就算谁的
public class PrioritizedParameterNameDiscoverer implements ParameterNameDiscoverer {
private final List<ParameterNameDiscoverer> parameterNameDiscoverers = new LinkedList<>();
public void addDiscoverer(ParameterNameDiscoverer pnd) {
this.parameterNameDiscoverers.add(pnd);
}
@Override
@Nullable
public String[] getParameterNames(Method method) {
for (ParameterNameDiscoverer pnd : this.parameterNameDiscoverers) {
String[] result = pnd.getParameterNames(method);
if (result != null) {
return result;
}
}
return null;
}
@Override
@Nullable
public String[] getParameterNames(Constructor<?> ctor) {
for (ParameterNameDiscoverer pnd : this.parameterNameDiscoverers) {
String[] result = pnd.getParameterNames(ctor);
if (result != null) {
return result;
}
}
return null;
}
}
那么接下来说说:StandardReflectionParameterNameDiscoverer和LocalVariableTableParameterNameDiscoverer
StandardReflectionParameterNameDiscoverer
Spring4.0提供 ,但是也得jdk8及以上版本使用。
Java.lang.reflect 包中提供了很多方法,获取所有的方法,获取所有的参数类型等,但是却没有一个方法能够帮助我们获取方法的参数名列表。JDK提供了方法弥补了这个缺陷。
public class StandardReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
@Override
@Nullable
public String[] getParameterNames(Method method) {
return getParameterNames(method.getParameters());
}
@Override
@Nullable
public String[] getParameterNames(Constructor<?> ctor) {
return getParameterNames(ctor.getParameters());
}
// 因为Parameter这个类是JDK8以上才提供的
@Nullable
private String[] getParameterNames(Parameter[] parameters) {
String[] parameterNames = new String[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Parameter param = parameters[i];
if (!param.isNamePresent()) {
return null;
}
parameterNames[i] = param.getName();
}
return parameterNames;
}
}
LocalVariableTableParameterNameDiscoverer
Spring2.0就有了,对JDK版本没啥要求,完全Spring自己实现的获取字段名称,逻辑复杂些,效率稍微低一点。
原理是:通过ASM提供的通过字节码获取方法的参数名称,Spring给我们集成了这个类,我们只需要简单的使用即可。
这个处理在我们Controller方法入参自动映射时,我们发现我们并不需要写@RequestParam("aaa")这样的注解,也能给自动映射上值,其实底层就运用了它去把这个key分析出来,然后去request里面拿的。
下面来看一个例子:
public class Main {
private static final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
public void testArguments(String test, Integer myInteger, boolean booleanTest) {
}
public void test() {
}
public static void main(String[] args) {
Method[] methods = Main.class.getDeclaredMethods();
for (Method method : methods) {
String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
System.out.println("方法:" + method.getName() + " 参数为:" + Arrays.asList(parameterNames));
}
}
}
输出为:
方法:main 参数为:[args]
方法:test 参数为:[]
方法:testArguments 参数为:[test, myInteger, booleanTest]
接下来,我们什么都不改,只改一句话:
private static final ParameterNameDiscoverer parameterNameDiscoverer = new StandardReflectionParameterNameDiscoverer();
运行看看效果:也能得出一样的效果
方法:main 参数为:[args]
方法:test 参数为:[]
方法:testArguments 参数为:[test, myInteger, booleanTest]
这里面需要特别注意了,StandardReflectionParameterNameDiscoverer的使用条件有两个
- JDK8以上版本
- 必须编译的时候有带上参数:javac -parameters
那么有小伙伴就疑问了,为何我上面编译没加参数也好使呢?这里面小伙伴务必注意了:如果你使用的idea的IDE,它里面默认编辑就带有此参数的:(Compiler-Java Compiler)
若你把它去掉,你的结果会如下:
// 去掉这个参数后,获取到的parameterNames 就是null了
// 再次提示一下:若还没效果,请手动重新编译对应文件
String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
为了获取最好的兼容性,推荐使用DefaultParameterNameDiscoverer,而不是直接使用某个具体的Discoverer
AutowireCandidateResolver
策略接口,对特定的依赖,这个接口决定一个特定的bean definition是否满足作为自动绑定的备选项。
// 本接口Spring2.5就提供了
public interface AutowireCandidateResolver {
default boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
return bdHolder.getBeanDefinition().isAutowireCandidate();
}
// Spring5.0后提供
default boolean isRequired(DependencyDescriptor descriptor) {
return descriptor.isRequired();
}
// 3.0后提供
@Nullable
default Object getSuggestedValue(DependencyDescriptor descriptor) {
return null;
}
// 4.0后提供
@Nullable
default Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
return null;
}
}
继承关系如下:
- SimpleAutowireCandidateResolver没有任何实现,就是一个Adapter
- GenericTypeAwareAutowireCandidateResolver:基础实现,有核心逻辑方法:checkGenericTypeMatch(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor),
作用为:根据给定的候选bean定义,将给定的依赖类型与其泛型类型信息匹配。(这就是泛型依赖注入的核心匹配逻辑,所以这其实也是Spring4.0后才推出来的)
protected boolean checkGenericTypeMatch(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
ResolvableType dependencyType = descriptor.getResolvableType();
if (dependencyType.getType() instanceof Class) {
// No generic type -> we know it's a Class type-match, so no need to check again.
return true;
}
ResolvableType targetType = null;
boolean cacheType = false;
RootBeanDefinition rbd = null;
if (bdHolder.getBeanDefinition() instanceof RootBeanDefinition) {
rbd = (RootBeanDefinition) bdHolder.getBeanDefinition();
}
if (rbd != null) {
targetType = rbd.targetType;
if (targetType == null) {
cacheType = true;
// First, check factory method return type, if applicable
targetType = getReturnTypeForFactoryMethod(rbd, descriptor);
if (targetType == null) {
RootBeanDefinition dbd = getResolvedDecoratedDefinition(rbd);
if (dbd != null) {
targetType = dbd.targetType;
if (targetType == null) {
targetType = getReturnTypeForFactoryMethod(dbd, descriptor);
}
}
}
}
}
if (targetType == null) {
// Regular case: straight bean instance, with BeanFactory available.
if (this.beanFactory != null) {
Class<?> beanType = this.beanFactory.getType(bdHolder.getBeanName());
if (beanType != null) {
targetType = ResolvableType.forClass(ClassUtils.getUserClass(beanType));
}
}
// Fallback: no BeanFactory set, or no type resolvable through it
// -> best-effort match against the target class if applicable.
if (targetType == null && rbd != null && rbd.hasBeanClass() && rbd.getFactoryMethodName() == null) {
Class<?> beanClass = rbd.getBeanClass();
if (!FactoryBean.class.isAssignableFrom(beanClass)) {
targetType = ResolvableType.forClass(ClassUtils.getUserClass(beanClass));
}
}
}
if (targetType == null) {
return true;
}
if (cacheType) {
rbd.targetType = targetType;
}
if (descriptor.fallbackMatchAllowed() && targetType.hasUnresolvableGenerics()) {
return true;
}
// Full check for complex generic type match...
return dependencyType.isAssignableFrom(targetType);
}
@Nullable
protected RootBeanDefinition getResolvedDecoratedDefinition(RootBeanDefinition rbd) {
BeanDefinitionHolder decDef = rbd.getDecoratedDefinition();
if (decDef != null && this.beanFactory instanceof ConfigurableListableBeanFactory) {
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) this.beanFactory;
if (clbf.containsBeanDefinition(decDef.getBeanName())) {
BeanDefinition dbd = clbf.getMergedBeanDefinition(decDef.getBeanName());
if (dbd instanceof RootBeanDefinition) {
return (RootBeanDefinition) dbd;
}
}
}
return null;
}
@Nullable
protected ResolvableType getReturnTypeForFactoryMethod(RootBeanDefinition rbd, DependencyDescriptor descriptor) {
// Should typically be set for any kind of factory method, since the BeanFactory
// pre-resolves them before reaching out to the AutowireCandidateResolver...
ResolvableType returnType = rbd.factoryMethodReturnType;
if (returnType == null) {
Method factoryMethod = rbd.getResolvedFactoryMethod();
if (factoryMethod != null) {
returnType = ResolvableType.forMethodReturnType(factoryMethod);
}
}
if (returnType != null) {
Class<?> resolvedClass = returnType.resolve();
if (resolvedClass != null && descriptor.getDependencyType().isAssignableFrom(resolvedClass)) {
// Only use factory method metadata if the return type is actually expressive enough
// for our dependency. Otherwise, the returned instance type may have matched instead
// in case of a singleton instance having been registered with the container already.
return returnType;
}
}
return null;
}
- QualifierAnnotationAutowireCandidateResolver:对@Qualifier的解析,功能是将qualifier注解要自动绑定的field或者参数和bean definition qualifier相匹配。同时也支持通过@value注解来绑定表达式的值。另外还支持JSR-330的javax.inject.Qualifier注解
- ContextAnnotationAutowireCandidateResolver:对@Lazy的解析
@Required:依赖检查;@Autowired:自动装配(可完全代替基于xml的装配)
@Value(value = “SpEL表达式”) 或者 @Value(value = “#{message}”)
@Qualifier:限定描述符,用于细粒度选择候选者
@Inject:等价于默认的@Autowired,只是没有required属性(支持@Primary)
- QualifierAnnotationAutowireCandidateResolver#getSuggestedValue:处理标注了@Value注解的情况
private Class<? extends Annotation> valueAnnotationType = Value.class;
// 拿到value注解的这个属性(若标注有@Value注解的话)
@Override
@Nullable
public Object getSuggestedValue(DependencyDescriptor descriptor) {
Object value = findValue(descriptor.getAnnotations());
if (value == null) {
// 看看方法有没有标注
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
value = findValue(methodParam.getMethodAnnotations());
}
}
return value;
}
/**
* Determine a suggested value from any of the given candidate annotations.
*/
@Nullable
protected Object findValue(Annotation[] annotationsToSearch) {
// 寻找到@Value注解的value属性值
AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(
AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);
if (attr != null) {
return extractValue(attr);
}
return null;
}
/**
* Extract the value attribute from the given annotation.
* @since 4.3
*/
protected Object extractValue(AnnotationAttributes attr) {
Object value = attr.get(AnnotationUtils.VALUE);
if (value == null) {
throw new IllegalStateException("Value annotation must have a value attribute");
}
return value;
}
Aware 容器感知技术
Spring的依赖注入的最大亮点:就是你所有的Bean对Spring容器的存在是没有意识的(我们的Bean并不需要实现它的任何接口)。即你可以将你的容器替换成别的容器,例如Goggle Guice,这时Bean之间的耦合度很低。
但是在实际的项目中,我们不可避免的要用到Spring容器本身的功能资源,这时候Bean必须要意识到Spring容器的存在,才能调用Spring所提供的资源,这就是所谓的Spring Aware。其实Spring Aware本来就是Spring设计用来框架内部使用的,若使用了Spring Aware,你的Bean将会和Spring框架耦合。
Spring提供Aware接口能让Bean感知Spring容器的存在,即让Bean可以使用Spring容器所提供的资源,下面是它提供给我们的感知器,我们一一简单介绍即可
- ApplicationContextAware:获取容器上下文
- BeanClassLoaderAware:获取加载当前Bean的类加载器
- BeanNameAware:获取当前Bean的名称
- LoadTimeWeaverAware:可以接收一个指向载入时(编译时)时织入实例的引用,实现编译时代理,属于比较高端的。可参见AspectJWeavingEnabler
- BootstrapContextAware:拿到资源适配器BootstrapContext上下文,如JCA,CCI
- ServletConfigAware:获取到ServletConfig
- ImportAware:获取到AnnotationMetadata等信息。这个挺重要的,比如AbstractCachingConfiguration、AbstractTransactionManagementConfiguration都通过实现这个接口来获取到了注解的属性们。比如@EnableAsync、EnableCaching等注解上的属性值。参考:Spring的@Import注解与ImportAware接口
- EmbeddedValueResolverAware:能让我们拿到StringValueResolver这个处理器,这样我们就可以很好的处理配置文件的值了。我们可以做个性化处理(比如我们自己要书写一个属性获取的工具类之类的)
- EnvironmentAware:拿到环境Environment
- BeanFactoryAware:获取Bean Factory
- NotificationPublisherAware:和JMX有关
- ResourceLoaderAware:获取资源加载器ResourceLoader可以获得外部资源文件 比如它的:ResourceLoader#getResource方法
- MessageSourceAware:获取国际化文本信息
- ServletContextAware:获取ServletContext
- ApplicationEventPublisher:拿到事件发布器
备注:在高版本的Spring容器中,这些基础组件基本上(大多数)都能直接Autowired了,比如ApplicationContext、BeanFactory等等,有时候使用起来更加的方便
ResolvableType:可解决的数据类型(更好的处理泛型)
Spring为我们提供的ResolvableType:它为java语言中的所有类型提供了相同的数据结构,其内部封装了一个java.lang.reflect.Type类型的对象。
ResolvableType为所有的java类型提供了统一的数据结构以及API ,换句话说,一个ResolvableType对象就对应着一种java类型。 下面我们看看具体的使用。
获取对象
ResolvableType所有构造函数都是私有的。我们不能直接new,只能使用其提供的静态方法进行类型获取。
public static ResolvableType forClass(@Nullable Class<?> clazz);
public static ResolvableType forRawClass(@Nullable Class<?> clazz);
public static ResolvableType forClass(Class<?> baseType, Class<?> implementationClass);
public static ResolvableType forMethodReturnType(Method method); //获取指定方法的返回值的类型
...见下面截图,非常非常多
部分方法:
- getSuperType():获取直接父类型
- getInterfaces():获取接口类型们
- getGenerics():获取类型携带的泛型类型
- resolve():Type对象到Class对象的转换(使用得非常多)
- isInstance、isAssignableFrom
- ResolvableType.forInstance 获取指定的实例的泛型信息
示例:
public static void main(String[] args) {
ResolvableType type = ResolvableType.forClass(ArrayList.class);
System.out.println(type); //java.util.ArrayList<?>
System.out.println(type.getType()); //class java.util.ArrayList
System.out.println(type.getComponentType()); //?
System.out.println(type.getInterfaces()); //[Lorg.springframework.core.ResolvableType;@4b4523f8
System.out.println(type.getSuperType()); //java.util.AbstractList<?>
System.out.println(type.getRawClass()); //class java.util.ArrayList
System.out.println(type.getSource()); //class java.util.ArrayList
System.out.println(type.getGenerics()); //[Lorg.springframework.core.ResolvableType;@1f28c152
System.out.println(type.resolve()); //class java.util.ArrayList
}
Spring还提供了一个专门处理泛型的工具类:GenericTypeResolver,非常的强大。
比如常用使用场景:this.genericType = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), GenericDaoSupport.class);
还有:GenericTypeResolver.resolveParameterType…方法
参考链接: 【小家Spring】Spring标准处理组件大合集(ParameterNameDiscoverer、AutowireCandidateResolver、ResolvableType。。。) |