浅谈Spring注解驱动发展史

 

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

一、Spring1.X版本

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

二、Spring2.X版本

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.example"/>

</beans>

三、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<String> 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<String> getCandidateConfigurations(AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		List<String> 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.
	 * <p>Can be present in multiple JAR files.
	 */
	public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
		String factoryClassName = factoryClass.getName();
		try {
			Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			List<String> result = new ArrayList<String>();
			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的模式注解添加索引,以提升应用启动性能

官网的解释:

好了今天就聊这么多吧,,小伙伴感觉有收获就动动发财的小手给个小红心+关注哦。。。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值