曹工说Spring Boot源码(27)-- Spring的component-scan,光是include-filter属性的各种配置方式,就够玩半天了.md (4)

标注了这个注解的,我们就要把它扫描为bean,那么可以如下配置:

<context:component-scan use-default-filters="false" base-package="org.springframework.test"> <context:include-filter type="annotation" expression="org.springframework.test.annotation.MyComponent"/> </context:component-scan>

注意,禁用掉默认的filter,避免干扰,可以看到,如下我们的测试类,是只注解了@MyComponent的:

@MyComponent public class Teacher { }

测试代码:

public static void testAnnotationFilter() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:component-scan-annotation-filter.xml"); Teacher bean = context.getBean(Teacher.class); System.out.println(bean); }

输出如下:

22:34:01.574 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'teacher'
org.springframework.test.annotation.Teacher@2bd7cf67

自定义typeFilter--扫描指定注解

事实上,component-scan允许我们定义多种类型的typeFilter,如AspectJ:

<context:component-scan use-default-filters="false" base-package="org.springframework.test"> <context:include-filter type="aspectj" expression="org.springframework.test.assignable.*"/> </context:component-scan>

只要满足这个路径的,都会被扫描为bean。

测试路径下,有如下类:

package org.springframework.test.assignable; public interface TestInterface { } public class TestInterfaceImpl implements TestInterface { }

测试代码:

static void testAspectj() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "classpath:component-scan-aspectj-filter.xml"); TestInterface bean = context.getBean(TestInterface.class); System.out.println(bean); }

输出如下:

22:37:22.347 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'testInterfaceImpl'

org.springframework.test.assignable.TestInterfaceImpl@3dea2f07

这个背后使用的typefilter,类型为:

org.springframework.core.type.filter.AspectJTypeFilter。

public class AspectJTypeFilter implements TypeFilter { private final World world; private final TypePattern typePattern; public AspectJTypeFilter(String typePatternExpression, ClassLoader classLoader) { this.world = new BcelWorld(classLoader, IMessageHandler.THROW, null); this.world.setBehaveInJava5Way(true); PatternParser patternParser = new PatternParser(typePatternExpression); TypePattern typePattern = patternParser.parseTypePattern(); typePattern.resolve(this.world); IScope scope = new SimpleScope(this.world, new FormalBinding[0]); this.typePattern = typePattern.resolveBindings(scope, Bindings.NONE, false, false); } // 1 public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { String className = metadataReader.getClassMetadata().getClassName(); ResolvedType resolvedType = this.world.resolve(className); return this.typePattern.matchesStatically(resolvedType); } }

代码1处,即:使用aspectj的方式,来判断是否候选的class是否匹配。

自定义typeFilter--指定类型的子类或实现类被扫描为bean

我们也可以这样配置:

<context:component-scan use-default-filters="false" base-package="org.springframework.test"> <context:include-filter type="assignable" expression="org.springframework.test.assignable.TestInterface"/> </context:component-scan>

这里的类型是assignable,只要是TestInterface的子类,即可以被扫描为bean。

其实现:

public class AssignableTypeFilter extends AbstractTypeHierarchyTraversingFilter { private final Class targetType; /** * Create a new AssignableTypeFilter for the given type. * @param targetType the type to match */ public AssignableTypeFilter(Class targetType) { super(true, true); this.targetType = targetType; } @Override protected boolean matchClassName(String className) { return this.targetType.getName().equals(className); } @Override protected Boolean matchSuperClass(String superClassName) { return matchTargetType(superClassName); } @Override protected Boolean matchInterface(String interfaceName) { return matchTargetType(interfaceName); } protected Boolean matchTargetType(String typeName) { if (this.targetType.getName().equals(typeName)) { return true; } else if (Object.class.getName().equals(typeName)) { return Boolean.FALSE; } else if (typeName.startsWith("java.")) { try { Class clazz = getClass().getClassLoader().loadClass(typeName); return Boolean.valueOf(this.targetType.isAssignableFrom(clazz)); } catch (ClassNotFoundException ex) { // Class not found - can't determine a match that way. } } return null; } }

总体来说,逻辑不复杂,反正就是:只要是我们指定的类型的子类或者接口实现,就ok。

自定义typeFilter--实现自己的typeFilter

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppdjd.html