浅谈Spring注解驱动发展史

 

前段时间自己在研究springboot的时候突然发现,springboot的诞生离不开spring注解驱动的支持,于是查询有关资料总结了spring注解驱动的发展史,

一、Spring1.X版本

众所周知spring的一重要特色就是IOC控制反转,帮助我们管理Bean及生命周期。其实这个重要特性也就是在spring的第一个版本发布的。但是这个时候我们在使用这个特性时是需要在applicationContext.xml中配置标签来使用,工程量巨大。并且搭建框架还需要配置dispatchservelet.xml等等

二、Spring2.X版本

在此版本迭代中比较重要的是Spring2.5这个版本,堪称经典版本,诞生了很多我们所熟悉的注解,比如:@Compontent、@Service、@Controller 。在这个版本中我们已经可以进行springMVC的分层架构了,controller层、service层、其它组件声明等。但是这里还是需要在.xml中配置相关参数,比如: 标签配置扫描路径/目录,除此之外集成其它组件比如: mysql/redis等也都需要在xml中配置相对应Bean的配置及参数




    

三、Spring3.X版本

这个版本在spring的发展史中堪称里程碑,因为在此版本中实现了完全去.xml化,推出了@Configration注解。现在我们配置一个模块或者组件可以这样做

@Configration
public class MybatisConfigration{

    @Bean
    public MybatisFactory MybatisFactory(){
        return new MybatisFactor();
    }

}

当然还有其它注解,比如:@Enable模块驱动  @Import 导入其它配置等。这两个注解其实是后来springboot自动装配特性的关键,正常情况我们使用@EnableSchule等注解可以直接启用一个模块,而不在需要配置其它相关的Bean,而在sprinboot中的启动类上有个@SpringBootApplication注解,这个注解是个复合注解,里面有个@EnableAutoConfigration注解,继续往里看,发现它里面有个@Import注解,,而这里正是springboot能够自动装配的关键,

看下源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}

看这个类:EnableAutoConfigurationImportSelector.class

源码:

public class AutoConfigurationImportSelector
		implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
		BeanFactoryAware, EnvironmentAware, Ordered {

	private static final String[] NO_IMPORTS = {};

	private static final Log logger = LogFactory
			.getLog(AutoConfigurationImportSelector.class);

	private ConfigurableListableBeanFactory beanFactory;

	private Environment environment;

	private ClassLoader beanClassLoader;

	private ResourceLoader resourceLoader;

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		try {
			AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
					.loadMetadata(this.beanClassLoader);

通过源码我们发现这个类继承了AutoConfigurationImportSelector类,而这个类最终实现了DeferredImportSelector接口,并且重写了selectImports这个方法,,这里返回的String【】数组就是所有待装配的className。

而如果想知道他是怎样扫描到这些配置类的,那我门可以继续往下看这段代码,getCandidateConfigurations类,获取候选配置的操作

List configurations = getCandidateConfigurations(annotationMetadata,
					attributes);

/**
	 * Return the auto-configuration class names that should be considered. By default
	 * this method will load candidates using {@link SpringFactoriesLoader} with
	 * {@link #getSpringFactoriesLoaderFactoryClass()}.
	 * @param metadata the source metadata
	 * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
	 * attributes}
	 * @return a list of candidate configurations
	 */
	protected List getCandidateConfigurations(AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		List configurations = SpringFactoriesLoader.loadFactoryNames(
				getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
		Assert.notEmpty(configurations,
				"No auto configuration classes found in META-INF/spring.factories. If you "
						+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

然后我们进去看看loader做了啥


/**
	 * The location to look for factories.
	 * 

Can be present in multiple JAR files. */ public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; public static List loadFactoryNames(Class factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List result = new ArrayList(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }

至此我们已经全然明白。

现在大家应该彻底搞清楚了吧。。不知不觉扯太多了,,回归正题哈哈

四、Spring4.X

这个版本也有个新的注解出现,就是@Conditional,条件注解,我们找个源码的应用来看它的使用,

 * @author Phillip Webb
 */
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {

注意条件是一个class,我们进去看下

 * @author Phillip Webb
 * @author Dave Syer
 * @author Jakub Kubrynski
 * @author Stephane Nicoll
 * @author Andy Wilkinson
 */
@Order(Ordered.LOWEST_PRECEDENCE)
class OnBeanCondition extends SpringBootCondition implements ConfigurationCondition {

	/**
	 * Bean definition attribute name for factory beans to signal their product type (if
	 * known and it can't be deduced from the factory bean class).






/**
 * Base of all {@link Condition} implementations used with Spring Boot. Provides sensible
 * logging to help the user diagnose what classes are loaded.
 *
 * @author Phillip Webb
 * @author Greg Turnquist
 */
public abstract class SpringBootCondition implements Condition {

	private final Log logger = LogFactory.getLog(getClass());

	@Override
	public final boolean matches(ConditionContext context,
			AnnotatedTypeMetadata metadata) {
		String classOrMethodName = getClassOrMethodName(metadata);
		try {
			ConditionOutcome outcome = getMatchOutcome(context, metadata);
			logOutcome(classOrMethodName, outcome);
			recordEvaluation(context, classOrMethodName, outcome);
			return outcome.isMatch();
		}

发现它继承的类SpringBootCondition实现了一个Condition接口,并且重写了matches方法,通过方法返回的boolean值来决定是否加载该Bean。这就是@Condition注解的用法。

五、Spring5.X

这个版本没有太多新的业务功能注解出现,,只有个@Indexed ,,主要在spring扫描多个配置路径时优化其效率的,它可以为Spring的模式注解添加索引,以提升应用启动性能

官网的解释:

浅谈Spring注解驱动发展史_第1张图片好了今天就聊这么多吧,,小伙伴感觉有收获就动动发财的小手给个小红心+关注哦。。。。。

你可能感兴趣的:(spring,spring,spring,boot)