Spring核心之注解开发历史

Spring注解开发的发展历程

image-20231031221112462

Spring1.x注解驱动启蒙时期

2004年3月24日,Spring1.0正式发布,提供了xml配置的方式,在该版本中必须要提供xml的配置文件,通过<bean>标签来配置需要被Spring容器管理的bean

1
2
3
4
5
6
7
8
9
10
11
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<bean id="user" class="com.huling.entity.User">
<property name="name" value="tom"></property>
<property name="age" value="22"></property>
</bean>
</beans>

在Spring1.2版本的时候提供了@Transactional注解,简化了事务的操作:

image-20231031222846162

Spring2.x注解驱动过渡时期

在Spring 2.5版本之前新增的有@Required@Repository@Aspect,同时也扩展了xml的配置能力,提供了第三方的扩展标签,比如<dubbo>

  • @Required:如果你在某个Java类的某个Setter方法上使用了该注释,那么该Setter方法对应的属性在xml配置文件中必须被设置,否则就会报错。

image-20231031224105159

  • @Repository:这个注解也是在2.0版本就提供了,对应DAO数据访问层的Bean。

image-20231031224322408

  • @Aspect:@Aspect是AOP相关的一个注解,用来标识切面配置类。

image-20231031224624733

Spring2.5版本之后,新增了很多常用注解,大大简化了配置操作:

注解 说明
@Autowired Bean的依赖注入
@Qualifier 配合Autowired注解使用
@Component 声明组件
@Service 声明业务层组件
@Controller 声明控制层组件
@RequestMapping 声明请求对应的处理方法

在这些注解的作用下,我们可以不用在xml文件中去定义bean,这时我们只需要指定代码扫描路径,然后在对应Java Bean类的头部添加相关的注解即可,这大大的简化了我们的配置及维护工作。我们在xml文件中只需要配置扫描路径即可:

1
2
3
4
5
6
7
8
9
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="com.huling"/>

</beans>

虽然在Spring的2.5版本提供了很多的注解,也大大的简化了我们的开发,但是仍然没有摆脱xml文件。

Spring3.x注解驱动黄金时期

2009年12月16日发布了Spring 3.0版本,这是一个注解编程发展的里程碑版本,在该版本中提供了@Configuration注解,目的就是去xml化。同时通过@ImportResource来实现Java配置类和xml配置的混合使用,来实现平稳过渡。

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class MyConfig {

/**
* @Bean注解标注的方法就相当于<bean>标签,也是Spring 3.0提供的注解
*/
@Bean
public User user() {
return new User();
}
}

在Spring 3.1版本之前,我们要配置扫描路径还只能在xml文件中通过<context:component-scan base-package="com.huling"/>来实现,还不能够完全实现去xml配置。Spring 3.1版本到来之后,提供了@ComponentScan注解,该注解的作用就是替换掉<context:component-scan>标签,是注解编程很大的进步,也是Spring实现无配置化的坚实基础。

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
@ComponentScan(value = "com.huling")
public class MyConfig {

/**
* @Bean注解标注的方法就相当于<bean>标签,也是Spring3.0提供的注解
*/
@Bean
public User user() {
return new User();
}
}

SpringBoot项目的启动类会加一个@SpringBootApplication注解,会指定当前项目要扫描的包路径,这个注解里面就内嵌了@ComponentScan注解。

@ImportResource注解用于整合配置类和xml配置文件:

1
2
3
4
5
6
@ImportResource("classpath:applicationContext.xml")
@Configuration
@ComponentScan(value = "com.huling.dao")
public class MyConfig {

}

@Import注解只能用在类上,作用是快速的将指定的类实例导入到Spring的IOC容器中:

1
2
3
4
5
6
@Import(User.class)
@Configuration
@ComponentScan(value = "com.huling.dao")
public class MyConfig {

}

测试注解:

1
2
3
4
5
@Test
public void test() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
}

image-20231031232438209

通过这个例子,我们还可以发现,@Import导入的实例对象,bean的名称是类的全路径,这种方式的好处是简单、直接,但是缺点是如果要导入的对象比较多,则不太方便,不够灵活。

@Import注解中也可以指定一个实现了ImportSelector接口的类型,这时Spring不会将@Import注解中指定的对象类型导入到IOC容器中,而是会调用ImportSelector接口中的selectImports方法,该方法会返回一个String类型的数组,该数组表示需要导入到IOC容器中的对象名称,通过该返回值告诉Spring哪些bean需要被导入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{
User.class.getName(),
Product.class.getName()
};
}
}

@Import(MyImportSelector.class)
@Configuration
@ComponentScan(value = "com.huling.dao")
public class MyConfig {

}

再次测试注解:

image-20231031232713814

可以看到,确实导入了两个实体类到IOC容器中,且没有导入MyImportSelector类。

@Import注解还可以导入其他配置类,用于整合多个分散的Config类,类似下面的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class OtherConfig {
@Bean
public Product product() {
return new Product();
}
}

@Import(OtherConfig.class)
@Configuration
@ComponentScan(value = "com.huling.dao")
public class MyConfig {

}

现在软件系统的开发,越来越按照模块化来了,这时如果我们需要什么模块,可以有选择性的导入到自己的系统中。@EnableXXX注解就提供了这个功能。这个注解的使用方式一般都是在定义@EnableXXX注解的时候内嵌一个@Import注解,然后通过@Import的特性导入具体的功能模块。这里给一个定义@EnableCaching的案例,具体的使用方式就不举例说明了,主要还是使用@Import的特性来实现的。

image-20231031233007171

Spring4.x注解驱动完善时期

2013年11月1日发布的Spring 4.0版本,提供的核心注解是@Conditional,它的作用是按照一定的条件进行判断,满足条件就给容器注册bean实例。 @Conditional的定义为:

image-20231031233205614

Condition是个接口,需要实现matches方法,返回true则注入bean,false则不注入:

image-20231031233313588

关于Spring Event的使用可以参见:✅在Spring中如何使用Spring Event做事件驱动 (yuque.com)

Spring5.x注解驱动现在时期

2017年9月28日,Spring发布了5.0版本,5.0版本同时也是SpringBoot的底层实现。在SpringBoot应用场景中,大量使用@ComponentScan扫描,导致Spring模式的注解解析时间耗时增大,因此5.0版本引入@Indexed注解,为Spring模式注解添加索引。

image-20231031233437034