Spring注解源码解析

1. 前言
最近看代码的时候,发现AnnotationConfigApplicationContext中的构造方法中,初始化了两个类:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner。

这两个类我觉的是构成JavaConfig以及注解方式的核心,所以想写一下对两个类的解析。
2. AnnotatedBeanDefinitionReader(注解类型读取器)
这个类其实比较简单,这个类主要是注册了一些内置的BeanFactoryPostProcessor和BeanPostProcessor。

他的代码实现比较简单,基本上先判断容器内是否有这些bean,如果没有bean就去注册。

其中最主要的就是ConfigurationClassPostProcessor和AutowiredAnnotationBeanPostProcessor以及CommonAnnotationBeanPostProcessor。

其中ConfigurationClassPostProcessor在context.refresh中首先被调用,这个类的主要是用来解析诸如@Configuration、@Import、@Component以及ImportSelector接口以及ImportBeanDefinitionRegistrar接口的注册和调用。这个类之后我会专门去分析。

AutowiredAnnotationBeanPostProcessor这个类主要是用于解析@Autowaired这个注解的解析。之后也会重点分析。

CommonAnnotationBeanPostProcessor这个类主要是对@PostConstruct和@PreDestory注解的解析。
2.1 下面分析一下,AnnotatedBeanDefinitionReader的registerBean方法。
//直接将配置类放入,当前类可以不使用@Configuration注解。但是基于规范,应该使用 @Configuration
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
	//this(); 这里将构造器直接放到下面了,便于查看
	this.reader = new AnnotatedBeanDefinitionReader(this);
	this.scanner = new ClassPathBeanDefinitionScanner(this);
	
	register(annotatedClasses);
	refresh();
}

//实际就是AnnotatedBeanDefinitionReader去将传进来的Configuration类做解析。
public void register(Class<?>... annotatedClasses) {
	Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
	this.reader.register(annotatedClasses);
}
public void register(Class<?>... annotatedClasses) {
	for (Class<?> annotatedClass : annotatedClasses) {
		registerBean(annotatedClass);
	}
}
public void registerBean(Class<?> annotatedClass) {
	doRegisterBean(annotatedClass, null, null, null);
}

/**
 * @param annotatedClass-javaConfig配置
 * 其他参数为null,应该是别的类做扩展用,这里不再讨论
 **/
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
		@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
    //AnnotatedBeanDefinition跟RootBeanDefinition属于同一层次。就是定义的Bean的一个在Spring容器内的原始封装对象
	AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
	    //这里看到,这个class被封装成为一个对象,这个对象里面包括了一个所谓的标准注解元数据。
	    public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
	        setBeanClass(beanClass);
	        this.metadata = new StandardAnnotationMetadata(beanClass, true);
	            //通过这里可以看到这个标准注解元数据将配置类的所有注解获取了。
	            public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
                	super(introspectedClass);
                	this.annotations = introspectedClass.getAnnotations();
	                this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
                    }
        }
	
	//这个方法我不再分析了,但是这里有一个很有意思的东西。如何判断一个类是否有某个注解
	//AnnotatedElementUtils可以使用这个类的hasMetaAnnotationTypes(AnnotatedElement element, String annotationName) 来判断。
	//AnnotatedElement这个东西很有意思,他的实现类是Class类。所以get的一个新技能
	//AnnotatedElement element = Object.class
	if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
		return;
	}
	abd.setInstanceSupplier(instanceSupplier);
	//这行代码就是将Scope注解解析出来封装成一个ScopeMetadata(scope元数据)对象
	ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
	//将Scope的作用域设置到当前的这个配置类的作用域下
	abd.setScope(scopeMetadata.getScopeName());
	//生成beanName。有value值用value,没有的话类名首字母小写(这里逻辑比较简单也不分析了)
	String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    
    //解析一些基本注解
	AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
	    //具体实现。将一些基本元素添加到AnnotatedBeanDefinition中,例如是否懒加载、角色等等
		static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
    		AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
    		if (lazy != null) {
    			abd.setLazyInit(lazy.getBoolean("value"));
    		}
    		else if (abd.getMetadata() != metadata) {
    			lazy = attributesFor(abd.getMetadata(), Lazy.class);
    			if (lazy != null) {
    				abd.setLazyInit(lazy.getBoolean("value"));
    			}
    		}
    		if (metadata.isAnnotated(Primary.class.getName())) {
    			abd.setPrimary(true);
    		}
    		AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
    		if (dependsOn != null) {
    			abd.setDependsOn(dependsOn.getStringArray("value"));
    		}
    
    		AnnotationAttributes role = attributesFor(metadata, Role.class);
    		if (role != null) {
    			abd.setRole(role.getNumber("value").intValue());
    		}
    		AnnotationAttributes description = attributesFor(metadata, Description.class);
    		if (description != null) {
    			abd.setDescription(description.getString("value"));
    		}
	    }
	
	//qualifiers==null
	if (qualifiers != null) {
		for (Class<? extends Annotation> qualifier : qualifiers) {
			if (Primary.class == qualifier) {
				abd.setPrimary(true);
			}
			else if (Lazy.class == qualifier) {
				abd.setLazyInit(true);
			}
			else {
				abd.addQualifier(new AutowireCandidateQualifier(qualifier));
			}
		}
	}
    //definitionCustomizers==null
	for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
		customizer.customize(abd);
	}
    
    //将bean对象(配置类)再次封装BeanDefinitionHolder==bean定义类+名称+别称
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	//将该对象注册到spring容器中    
    //实际上还是以registry.registerBeanDefinition(String beanName, BeanDefinition beanDefinition)实现
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
2.2 总结
这个AnnotatedBeanDefinitionReader类做了以下几件事:
1.初始化了内部一个BeanFactoryPostProcessor和BeanPostProcessor。
2.将初始化传进来的的配置类注册到Spring容器中。
3. ClassPathBeanDefinitionScanner(类路径扫描器)
这个类是在AnnotationConfigApplicationContext构造方法中初始化的,看上面代码。
这里为什么重点想说一下这个类,这个类其实是在xml里面出现而使用的。通过代码注释可以看到它最早在Spring2.5就已经在使用了。而AnnotationConfigApplicationContext这个类在Spring3.0的时候才有。这里可以看到代码的复用是很重要的。
3.1 分析方法
/**
 *  1.Bean注册类-->就是AnnotationConfigApplicationContext
 *  2.是否使用默认过滤器(这个过滤器是用来过滤如 @Component、@Service、@Controller、@Repository以及自定义Bean注解类) 这里我觉得可以把 @Component当做Spring的元注解。
 *  3.系统环境 --这里的环境指的是什么? 我现在的看法指的是系统参数,例如我们在加载main方法指定的一些参数。这里我看到的代码是从System.getProperties()获取一些参数。
 *  4.类加载器
 */
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
		Environment environment, @Nullable ResourceLoader resourceLoader) {
	this.registry = registry;
    
	if (useDefaultFilters) {
		registerDefaultFilters();   
		    //由此可以看到是添加一些过滤注解
		    protected void registerDefaultFilters() {
        		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
        		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
        		try {
        			this.includeFilters.add(new AnnotationTypeFilter(
        					((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
        			logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
        		}
        		catch (ClassNotFoundException ex) {
        			// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
        		}
        		try {
        			this.includeFilters.add(new AnnotationTypeFilter(
        					((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
        			logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
        		}
        		catch (ClassNotFoundException ex) {
        			// JSR-330 API not available - simply skip.
        		}
        	}
	}
	setEnvironment(environment);
	setResourceLoader(resourceLoader);
}

//再来看下AnnotationConfigApplicationContext的另一种构造方法,扫描指定路径下的文件注册为Bean
public AnnotationConfigApplicationContext(String... basePackages) {
	this();
	scan(basePackages);
	refresh();
}


public void scan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	this.scanner.scan(basePackages);
}

public int scan(String... basePackages) {
	int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

	doScan(basePackages);

	// Register annotation config processors, if necessary.
	if (this.includeAnnotationConfig) {
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

	return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}


protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
	//遍历
	for (String basePackage : basePackages) {
	    //通过方法名称可知找到Component注解标注的类作为Bean(candidate--候选人)
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		for (BeanDefinition candidate : candidates) {
		    //拿到Scope元素
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			candidate.setScope(scopeMetadata.getScopeName());
			//beanName生成
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			//加载公共参数
			if (candidate instanceof AbstractBeanDefinition) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			if (candidate instanceof AnnotatedBeanDefinition) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			//校验名称是否存在
			if (checkCandidate(beanName, candidate)) {
			    //生成一个包装类
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				//生产scope代理类
				definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);
				//注册bean
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    //这个if其实没搞太清楚,但是从方法名字可以知道应该是带有编号或者索引的查找
	if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
		return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
	}
	else {
		return scanCandidateComponents(basePackage);
	}
}


private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
	Set<BeanDefinition> candidates = new LinkedHashSet<>();
	try {
	    //这里拼接了一个完整路径 classpath*:xxxx/**/*.class
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		//转换成资源类
		Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (Resource resource : resources) {
			if (traceEnabled) {
				logger.trace("Scanning " + resource);
			}
			if (resource.isReadable()) {
				try {
				    //getMetadataReaderFactory获取的是CachingMetadataReaderFactory
				    //MetadataReader获取的是SimpleMetadataReader
				    //这里知道获取的是那个对象即可,不再往下追踪代码,因为底层代码用了大量的字节码技术,这块我自己不清楚。
				    //这块代码就是获取了一个元数据读取器,这个元数据读取器包括了Resource(原始资源 字节流)、ClassMetadata(跟类相关的元数据,例如类名称、是否是接口、是否是final类型等等)、AnnotationMetadata(该类的注解元数据,就是这个类注解上所有的信息)
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
					//判断是否为 @Component注解标注的类(这里不只是Component,只要是在过滤器里面的都会返回true)
					if (isCandidateComponent(metadataReader)) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setResource(resource);
						sbd.setSource(resource);
						if (isCandidateComponent(sbd)) {
							if (debugEnabled) {
								logger.debug("Identified candidate component class: " + resource);
							}
							candidates.add(sbd);
		//下面都是关于日志打印的,去掉了
		....
3.2 总结
其实从上面的分析可以看出来,ClassPathBeanDefinitionScanner主要是对指定路径下 @Component注解的类 注册为Bean。
通过添加新的过滤器,用于自定义注解的类把他注册为一个bean。
还有解析注解的时候可以使用MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
4.代码实践
4.1 ClassPathBeanDefinitionScanner代码实践
主类
public class ClassPathScannerTest {

    public static void main(String[] args) {
        
        //定义了一个初始的BeanFactory
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //扫描器
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(factory);
        //添加自定义过滤器
        scanner.addIncludeFilter(new AnnotationTypeFilter(ModifyComponent.class));
        //扫描包路径
        scanner.scan("com.study.spring.scanner");
        String[] names = factory.getBeanDefinitionNames();
        Stream.of(names).forEach(System.out::println);

    }
}

自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ModifyComponent {
    String value() default "";
}


@Component
public class ScanTestBean1 {
}

@ModifyComponent
public class ScanTestBean2 {
}   
4.2 MetadataReader代码实践
public class MetaReaderTest {

public static void main(String[] args) throws IOException {
    MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
    //获取某个类的元数据类型
    MetadataReader metadataReader = metadataReaderFactory.getMetadataReader("com.study.spring.scanner"
            + ".ScanTestBean2");
    //注解元数据类型
    AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
    //类元数据类型
    ClassMetadata classMetadata = metadataReader.getClassMetadata();

    }
}

通过这个类可以很快的去判断类的一些特征数据,是一个很方便的工具类
5.源码总结
AnnotationConfigApplicationContext跟ClassPathXmlApplicationContext解析方式完全不同,毕竟一个依赖于xml配置文件去解析,一个依靠注解去解析。
AnnotationConfigApplicationContext相当于提供了两种方式:
1.注册配置类:
    需要手动指定一个配置类,然后通过AnnotatedBeanDefinitionReader把配置类注册成为一个bean。
2.扫描指定路径
    则通过ClassPathBeanDefinitionScanner去将 @Component 注解的类(包括父注解有@Component的类)注册成为一个bean。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值