【SpringBoot初识之Spring注解发展流程以及常用的Spring和SpringBoot注解】

一.Spring注解编程的发展过程

为了更好的学习SpringBoot的内容,我们先来学习Spring注解编程的发展过程,通过该过程的演变能够让大家更加清楚SpringBoot的由来。
image.png

1.1 Spring 1.x版本

  1. 2004年3月24日,Spring1.0 正式发布,提供了IOC,AOP及XML配置的方式。
  2. 在Spring1.x版本中提供的是纯XML配置的方式,也就是在该版本中我们必须要提供xml的配置文件,在该文件中我们通过 <bean> 标签来配置需要被IOC容器管理的Bean。

applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!--xml文件中配置Bean对象-->
    <bean class="com.ljw.service.UserService" />
</beans>

主函数调试代码

public class Main {

    public static void main(String[] args) {
        ApplicationContext applicationContext=new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
        System.out.println(applicationContext.getBean(UserService.class));
    }
}

输出结果

在这里插入图片描述

在Spring1.2版本的时候提供了@Transactional注解。简化了事务的操作.
在这里插入图片描述

在这里插入图片描述

1.2 Spring 2.x 版本

在2006年10月3日 Spring2.0问世了,在2.x版本中,比较重要的特点是增加了很多注解。

1.2.1 Spring 2.5之前

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

1.2.1.1 @Required

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

public class UserService {


    private String userName;

    public String getUserName() {
        return userName;
    }

    @Required
    public void setUserName(String userName) {
        this.userName = userName;
    }
}

如果在xml文件中我们不设置对应的属性就会给出错误的提示。设置好属性后就没有错误提示了。

在这里插入图片描述

源码中可以看到@Required从2.0开始提供

在这里插入图片描述

1.2.1.2 @Repository

@Repository 对应数据访问层Bean.这个注解在Spring2.0版本就提供。

在这里插入图片描述

1.2.1.3 @Aspect

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

1.2.2 Spring2.5 之后版本

在2007年11月19日,Spring更新到了2.5版本,新增了很多常用注解,大大的简化配置操作。

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

在这些注解的作用下,我们可以不用在xml文件中去注册bean,这时我们只需要指定扫码路径,然后在对应的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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	<!--配置文件配置扫描注解-->
    <context:component-scan base-package="com.ljw" />

</beans>

持久层代码:

@Repository
public class UserDao {

    public void selectUser(){
        System.out.println("查询一个user。。。。");
    }

}

业务逻辑层代码

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public void selectUser(){
        userDao.selectUser();
    }

}

控制层代码:

@Controller
public class UserController {

    @Autowired
    private UserService userService;

    public void selectUser(){
        userService.selectUser();
    }
}

测试代码

public class Main {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserController controller = applicationContext.getBean(UserController.class);
        controller.selectUser();
    }

}

结果展示:
在这里插入图片描述

虽然在Spring的2.5版本提供了很多的注解,也大大的简化了我们的开发,但是任然没有摆脱XML配置驱动。

1.3 Spring 3.x 版本

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

1.3.1 @Configuration注解
/**
 * @Configuration注解修饰的Java类相当于applicationContext.xml 配置文件
 */
@Configuration
public class Config{

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

在Spring3.1 版之前配置扫描路径我们还只能在 XML 配置文件中通过 component-scan标签来实现,在3.1之前还不能够完全实现去XML配置,在3.1 版本到来的时候,提供了一个@ComponentScan注解,该注解的作用是替换掉 component-scan标签,是注解编程很大的进步,也是Spring实现无配置话的坚实基础。

1.3.2 @ComponentScan注解

@ComponentScan的作用是指定扫码路径,用来替代在XML中的 <component-scan>标签,默认的扫码路径是当前注解标注的类所在的包及其子包。

定义UserService

@Service
public class StudentService{

}

创建对于的Java配置类

@Configuration
@ComponentScan
public class Main{

    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(Main.class);
        System.out.println(ac.getBean(StudentService.class));
    }
}

输出的结果

在这里插入图片描述

1.3.3 @Import注解

@Import注解只能用在类上,作用是快速的将实例导入到Spring的IOC容器中,将实例导入到IoC容器中的方式有很多种,比如 @Bean注解,@Import注解可以用于导入第三方包。具体的使用方式有三种。

1.3.3.1 静态导入

静态导入的方式是直接将我们需要导入到IOC容器中的对象类型直接添加进去即可。

@Configuration
@ComponentScan
@Import(UserDao.class)
public class Main {

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

}

在这里插入图片描述

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

1.3.3.2 ImportSelector

@Import注解中我们也可以添加一个实现了 ImportSelector接口的类型,这时不会将该类型导入IOC容器中,而是会调用 ImportSelector接口中定义的 selectImports方法,将该方法的返回的字符串数组的类型添加到容器中。

定义两个业务类

public class TestDemo1 {
}

public class TestDemo2 {
}

定义ImportSelector接口的实现,方法返回的是需要添加到IOC容器中的对象对应的类型的全类路径的字符串数组,我们可以根据不同的业务需求而导入不同的类型,会更加的灵活些。

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{TestDemo1.class.getName(), TestDemo2.class.getName()};
    }
}

测试代码

/**
 * @Import 注解中导入的类型如果实现了 ImportSelector 接口,不会将该类型注入到容器中
 *         而是会将selectImports的返回的类型的全类路径的字符串的数据注入到容器中
 *         动态注入
 */
@Configuration
@Import(MyImportSelector.class)
public class JavaConfig {

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

输出结果:

在这里插入图片描述

1.3.3.3 ImportBeanDefinitionRegistrar

除了上面所介绍的ImportSelector方式灵活导入以外还提供了 ImportBeanDefinitionRegistrar 接口,也可以实现,相比 ImportSelector 接口的方式,ImportBeanDefinitionRegistrar 的方式是直接在定义的方法中提供了 BeanDefinitionRegistry ,自己在方法中实现注册。

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata
            , BeanDefinitionRegistry registry) {
        RootBeanDefinition rootBeanDefinition =new RootBeanDefinition(TestDemo1.class);
        registry.registerBeanDefinition("TestDemo1",rootBeanDefinition);

        RootBeanDefinition rootBeanDefinition1 = new RootBeanDefinition(TestDemo2.class);
        registry.registerBeanDefinition("TestDemo2",rootBeanDefinition1);

    }
}

测试代码

/**
 * @Import 注解中导入的类型如果实现了 ImportSelector 接口,不会将该类型注入到容器中
 *         而是会将selectImports的返回的类型的全类路径的字符串的数据注入到容器中
 *         动态注入
 */
@Configuration
@Import({MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class JavaConfig {

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

输出结果

在这里插入图片描述

1.3.4 @EnableXXX

@Enable模块驱动,其实是在系统中我们先开发好各个功能独立的模块,比如 Web MVC 模块, AspectJ代理模块,Caching模块等。

在这里插入图片描述

先定义好功能模块

/**
 * 定义一个Java配置类
 */
@Configuration
public class TestConfiguration {

    @Bean
    public String test(){
        return "test";
    }
}

然后定义@EnableTest注解

/**
 * 定义@Enable注解
 * 在该注解中通过 @Import 注解导入我们自定义的模块,使之生效。
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HelloWorldConfiguration.class)
public @interface EnableTest {
}

测试代码

@Configuration
// 加载 自定义 模块
@EnableTest
public class Main{

    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(Main.class);
        String test = ac.getBean("test", String.class);
        System.out.println("test = " + test);
    }
}

结果展示:

在这里插入图片描述

1.4 Spring 4.x 版本

2013年11月1 日更新的Spring 4.0 ,完全支持Java8.这是一个注解完善的时代,提供的核心注解是@Conditional条件注解。@Conditional 注解的作用是按照一定的条件进行判断,满足条件就给容器注册Bean实例。

@Conditional的定义为:
在这里插入图片描述

// 该注解可以在 类和方法中使用
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

    /**
     * 注解中添加的类型必须是 实现了 Condition 接口的类型
     */
    Class<? extends Condition>[] value();

}

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

/**
 * 定义一个 Condition 接口的是实现
 */
public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return false; // 默认返回false
    }
}

创建Java配置类

@Configuration
public class JavaConfig {

    @Bean
    // 条件注解,添加的类型必须是 实现了 Condition 接口的类型
    // MyCondition的 matches 方法返回true 则注入,返回false 则不注入
    @Conditional(MyCondition.class)
    public StudentService studentService(){
        return new StudentService();
    }

    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
        for (String beanDefinitionName : ac.getBeanDefinitionNames()) {
            System.out.println("beanDefinitionName = " + beanDefinitionName);
        }
    }
}

结果展示:
在这里插入图片描述

结果设置为 true 则效果不同

在这里插入图片描述

所以@Conditional的作用就是给我们提供了对象导入IOC容器的条件机制,这也是SpringBoot中的自动装配的核心关键。当然在4.x还提供一些其他的注解支持,比如 @EventListener,作为ApplicationListener接口编程的第二选择,@AliasFor解除注解派生的时候冲突限制。@CrossOrigin作为浏览器跨域资源的解决方案。

1.5 Spring 5.x 版本

2017年9月28日,Spring来到了5.0版本。5.0同时也是SpringBoot2.0的底层。注解驱动的性能提升方面不是很明显。在Spring Boot应用场景中,大量使用@ComponentScan扫描,导致Spring模式的注解解析时间耗时增大,因此,5.0时代引入**@Indexed**,为Spring模式注解添加索引。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-indexer</artifactId>
</dependency>

使用@Indexed注解

@Indexed
public class StudentService {

}

在这里插入图片描述

当我们在项目中使用了 @Indexed之后,编译打包的时候会在项目中自动生成 META-INT/spring.components文件。当Spring应用上下文执行 ComponentScan扫描时,META-INT/spring.components将会被 CandidateComponentsIndexLoader 读取并加载,转换为 CandidateComponentsIndex对象,这样的话 @ComponentScan不在扫描指定的package,而是读取 CandidateComponentsIndex对象,从而达到提升性能的目的。

在这里插入图片描述

好了,到这里【SpringBoot初识之Spring注解发展流程以及常用的Spring和SpringBoot注解】就学习到这里,更多内容不断学习,不断创作中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

硕风和炜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值