Spring注解编程的发展过程

前言

Spring在2004年3月24日发布了1.0版本,到现在时间已经过去了快20年,产生的影响不可谓不大。期间也发布了好几个版本,现在已经到了6.x的版本,使用方式也在悄悄发生变化。现在可能大部分使用者都在用SpringBoot,但是归根结底,底层还是Spring。

Spring的更新迭代,不断简化着开发方式。这篇文章就介绍下Spring注解编程的发展过程。

timeline title 版本发展节点 section Spring 1.0
注解驱动启蒙时期 2004-03-24 : @Transactional section Spring 2.0
注解驱动过渡时期 2006-10-03 : @Required : @Repository : @Aspect : @Autowired : @Qualifier : @Component : @Service : @Controller : @RequestMapping section Spring 3.0
注解驱动黄金时期 2009-12-16 : @Configuration : @ImportResource : @ComponentScan : @Import section Spring 4.0
注解驱动完善时期 2013-11-01 : @Conditional : @EventListener : @AliasFor : @CrossOrigin section Spring 5.0
注解驱动成熟时期 2017-09-28 : @Indexed

发展过程

Spring 1.x

2004年3月24日,Spring 1.0正式发布,提供了xml配置的方式

在该版本中,必须要提供xml的配置文件,通过<bean>标签来配置需要被Spring容器管理的bean

xml 复制代码
<?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="cat" class="com.xiaojiesen.debug.xml.Cat">
       <property name="name" value="cat"></property>
       <property name="age" value="9"></property>
    </bean>
</beans>

调试代码

java 复制代码
public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("xmlContext.xml");
    Object cat = applicationContext.getBean("cat");
    System.out.println(cat);
}

在Spring 1.2版本的时候提供了@Transactional注解,简化了事务的操作

Spring 2.x

在2006年10月3日Spring 2.0问世了,在2.x版本中,增加了很多注解

Spring 2.5之前

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

  • @Required(2.0)

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

java 复制代码
public class Cat {

    private Integer age;

    private String name;

    public Integer getAge() {
       return age;
    }

    public void setAge(Integer age) {
       this.age = age;
    }

    public String getName() {
       return name;
    }

    @Required
    public void setName(String name) {
       this.name = name;
    }
}

如果在xml文件中不设置对应的属性,就会给出错误的提示

设置好属性后就没有错误提示了

  • @Repository(2.0)

这个注解也是在2.0版本就提供了,对应数据访问层的bean

  • @Aspect

@Aspect是AOP相关的一个注解,用来标识配置类

Spring 2.5之后

Spring 2.5版本之后,新增了很多常用注解,大大简化了配置操作

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

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

xml 复制代码
<?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.xiaojiesen.debug"/>  
  
</beans>

对应bean类:

java 复制代码
@Component
public class Cat {

    private Integer age;

    private String name;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

测试代码:

java 复制代码
	public static void main(String[] args) {
      ApplicationContext applicationContext = new ClassPathXmlApplicationContext("xmlContext.xml");
      Object cat = applicationContext.getBean("cat");
      System.out.println(cat);
	}

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

Spring 3.x

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

Java 复制代码
@Configuration
public class ContextConfig {

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

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

@ComponentScan

这个注解的作用是指定代码扫描路径,后面可以指定具体要扫描的代码路径也可以不指定;若不指定的话,默认的扫描路径就是当前注解标注的类所在的包及其子包。

java 复制代码
@Configuration
@ComponentScan(value = "com.xiaojiesen.debug.annotation")
public class ComponentScanConfiguration {

}

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

@Import

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

通过这个例子,我们还可以发现,@Import导入的实例对象,bean的名称是类的全路径,通过applicationContext.getBean("user")是获取不到对象的,会提示找不到user

这种方式的好处是简单、直接,但是缺点是如果要导入的对象比较多,则不太方便,不够灵活。

在SpringBoot项目中,可以看到大量使用@Import注解的地方,它一般跟@EnableXXX一起使用,如启用服务发现注解@EnableDiscoveryClient

@ImportSelector

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

举个例子,我们先定义两个业务类CacheLogger

Java 复制代码
public class Cache {  
}
Java 复制代码
public class Logger {  
}

再定义一个实现了ImportSelector接口的类型,selectImports方法返回上面两个业务类的全路径名称(这个接口的实现可以有不同的方式,这里为了简单直接返回了)

Java 复制代码
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{Cache.class.getName(), Logger.class.getName()};
    }
	
}

测试类

Java 复制代码
@Configuration
@Import(value = MyImportSelector.class)
public class ImportSelectorTest {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ImportSelectorTest.class);
        for (String name : applicationContext.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
}

输出结果:

可以看到,确实导入了两个业务类到IoC容器中,且没有导入MyImportSelector

@EnableXXX

现在软件系统的开发,越来越按照模块化来了,这时如果我们需要什么模块,可以有选择性的导入到自己的系统中。@EnableXXX注解就提供了这个功能。

这个注解的使用方式一般都是在定义@EnableXXX注解的时候内嵌一个@Import注解,然后通过@Import的特性导入具体的功能模块。这里给一个定义@EnableCaching的案例,具体的使用方式就不举例说明了,主要还是使用@Import的特性来实现的。

Spring 4.x

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

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

Spring 5.x

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

总结

写这篇文章主要是理一下脉络,为后面写Spring的文章提供一些前置知识,也算是做一下自己学习的总结。

相关推荐
瓜牛_gn1 小时前
Spring Security概述
spring
像污秽一样2 小时前
Spring MVC初探
java·spring·mvc
LuckyLay2 小时前
Spring学习笔记_36——@RequestMapping
java·spring boot·笔记·spring·mapping
RainbowSea2 小时前
4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明
java·spring·spring cloud
2401_857600954 小时前
深入剖析:Spring MVC与Struts的较量
struts·spring·mvc
被猫枕的咸鱼4 小时前
springmvc通过使用map来进行数据的接收和使用
spring
荆州克莱5 小时前
Big Data for AI实践:面向AI大模型开发和应用的大规模数据处理套件
spring boot·spring·spring cloud·css3·技术
酸奶代码7 小时前
Spring AOP技术
java·后端·spring
代码小鑫7 小时前
A034-基于Spring Boot的供应商管理系统的设计与实现
java·开发语言·spring boot·后端·spring·毕业设计
.生产的驴8 小时前
SpringCloud Gateway网关路由配置 接口统一 登录验证 权限校验 路由属性
java·spring boot·后端·spring·spring cloud·gateway·rabbitmq