Spring基于注解管理bean(一文搞懂注解及使用注解)

一、标记与扫描机制

1. 注解的作用

① 注解

和 XML 配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。

本质上:所有一切的操作都是Java代码来完成的,XML和注解只是告诉框架中的Java代码如何执行。

举例:在修建道路的时候为道路留下测量后的标记

测绘人员做了所有标记,工人们来完成具体工作。道路上的标记相当于我们在代码中使用的注解,后面施工团队做的工作,相当于框架的具体操作。

② 扫描

Spring 为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后根据注解进行后续操作。

2. 构建环境及测试注解

① 新建Module

在pomp文件配置依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.1</version>
    </dependency>
    <!-- junit测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>
  • 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包

② 创建Spring配置文件

在这里插入图片描述

③ 创建一组组件类

  1. 使用@Component注解标记的普通组件
package com.zengchuiyu.ioc.component;
import org.springframework.stereotype.Component;
/**
 * @author zengchuiyu
 * @create 2021-10-13 22:28
 */
@Component
public class OneComponent {
}
  1. 使用@Controller注解标记的控制器组件

    这个组件就是我们在三层架构中表述层里面,使用的控制器。以前是Servlet,我们使用Controller来代替Servlet。

package com.zengchuiyu.ioc.component;
import org.springframework.stereotype.Controller;
/**
 * @author zengchuiyu
 * @create 2021-10-13 22:30
 */
@Controller
public class StudentController {
}
  1. 使用@Service注解标记的业务逻辑组件

    这个组件就是我们在三层架构中使用的业务逻辑组件。

package com.zengchuiyu.ioc.component;
import org.springframework.stereotype.Service;
/**
 * @author zengchuiyu
 * @create 2021-10-13 22:31
 */
@Service
public class StudentService {
}
  1. 使用@Repository注解标记的持久化层组件

    这个组件就是我们以前用的Dao类,但是以后我们整合了Mybatis,这里就变成了Mapper接口,而Mapper接口是由Mybatis和Spring的整合包负责扫描的。

    由于Mybatis整合包想要把Mapper接口背后的代理类加入Spring的IOC容器需要结合Mybatis对Mapper配置文件的解析,所以这个事情是Mybatis和Spring的整合包来完成,将来由Mybatis负责扫描,也不使用@Repository注解。

package com.zengchuiyu.ioc.component;
import org.springframework.stereotype.Repository;
/**
 * @author zengchuiyu
 * @create 2021-10-13 22:32
 */
@Repository
public class StudentDao {
}

④ 四个典型注解本质是一样的

在这里插入图片描述
通过查看源码我们得知,@Controller、@Service、@Repository这三个注解只是在@Component注解的基础上起了三个新的名字。

注意:虽然它们本质上一样,但是为了代码的可读性,为了程序结构严谨我们也不能随便胡乱标记。

⑤ 扫描

  1. 情况一:最基本的扫描方式[常用]
<!-- 配置自动扫描的包 -->
    <context:component-scan base-package="com.zengchuiyu.ioc.component"/>

从IOC容器中获取bean:

在test文件夹中创建单元测试类:
在这里插入图片描述

public class TestAnno {
    //获取IOC容器对象
    private ApplicationContext context =
            new ClassPathXmlApplicationContext("applicationContext.xml");

    @Test
    public void test1(){
        //获取四个类的实例
        OneComponent oneComponent = context.getBean(OneComponent.class);
        StudentController studentController = context.getBean(StudentController.class);
        StudentService studentService = context.getBean(StudentService.class);
        StudentDao studentDao = context.getBean(StudentDao.class);

        System.out.println(oneComponent);
        System.out.println(studentController);
        System.out.println(studentService);
        System.out.println(studentDao);
    }
}

结果:

在这里插入图片描述
如图:四个对象都成功的在容器中获取到了,证明我们使用注解的方式装配对象成功了!

  1. 情况二:指定匹配模式
<!--在指定扫描包的基础上指定匹配模式-->
    <context:component-scan
            base-package="com.zengchuiyu.ioc.component"
            resource-pattern="Student*.class"/>

Student*表示以Student开头的类,所以OneComponent对象无法创建,在这就不一一测试。

  1. 情况三:指定要排除的组件
    <context:component-scan
            base-package="com.zengchuiyu.ioc.component">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
  • context:exclude-filter标签:指定排除规则
  • type属性:指定根据什么来进行排除,annotation取值表示根据注解来排除
  • expression属性:指定排除规则的表达式,对于注解来说指定全类名即可
  1. 情况四:仅扫描指定组件
<context:component-scan
            base-package="com.zengchuiyu.ioc.component"
            use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

在这里要说明并不是跟排除那样只写个context:include-filter标签指定就好,因为context:component-scan标签是默认扫描全部的,当指定扫描指定类时还要附加上取消默认过滤规则为false

⑥ 组件的唯一标识

在我们使用XML方式管理bean的时候,每个bean都有一个唯一标识,便于在其他地方引用。现在使用注解后,每个组件仍然应该有一个唯一标识。

  1. 默认情况

类名首字母小写就是bean的id。例如:StudentController类对应的bean的id就是studentController。

  1. 使用value属性指定
@Service(value = "zengchuiyu")
public class StudentService {
}

当注解中只设置一个属性时,value属性的属性名可以省略:

@Service("zengchuiyu")
public class StudentService {
}

二、自动装配

1. 应用场景

  • StudentController需要StudentService
  • StudentService需要StudentDao
    且在各个组件中声明了要调用的方法

① StudentController中声明的方法

@Controller
public class StudentController {

    private StudentService studentService;

    public void getMessage(){
        studentService.getMessage();
    }

}

② StudentService中声明的方法

@Service(value = "zengchuiyu")
public class StudentService {

    private StudentDao studentDao;

    public void getMessage(){
        studentDao.getMessage();
    }

}

③ StudentDao中声明的方法

@Repository
public class StudentDao {

    public void getMessage(){
        System.out.println("I am a student!");
    }

}

2. 自动装配的实现

① 前提

参与自动装配的组件(需要装配别人、被别人装配)全部都必须在IOC容器中。

② @Autowired注解
在成员变量上直接标记@Autowired注解即可,不需要提供setXxx()方法。

在这里插入图片描述

在这里插入图片描述

3. @Autowired注解其他细节

① 标记在其他位置

  • 构造器
@Controller
public class StudentController {

    private StudentService studentService;

    public void getMessage(){
        studentService.getMessage();
    }
@Autowired
    public void setStudentService(StudentService studentService) {
        this.studentService = studentService;
    }
	@Autowired
    public StudentController(StudentService studentService) {
        this.studentService = studentService;
    }
}
  • setXxx()方法
@Controller
public class StudentController {

    private StudentService studentService;

    public void getMessage(){
        studentService.getMessage();
    }
	@Autowired
    public void setStudentService(StudentService studentService) {
        this.studentService = studentService;
    }
}

这两种方式都可以实现自动装配,但是出于习惯以及方便我们还是常用局部变量直接注册比较多

②@Autowired工作流程

在这里插入图片描述
首先根据所需要的组件类型到IOC容器中查找

  • 能够找到唯一的bean:直接执行装配

  • 如果完全找不到匹配这个类型的bean:装配失败

和所需类型匹配的bean不止一个

  • 没有@Qualifier注解:根据@Autowired标记位置成员变量的变量名作为bean的id进行匹配

  • 能够找到:执行装配

  • 找不到:装配失败

  • 使用@Qualifier注解:根据@Qualifier注解中指定的名称作为bean的id进行匹配

  • 能够找到:执行装配

  • 找不到:装配失败

@Controller
public class StudentController {
    @Qualifier(value = "One")
    @Autowired
    private StudentService studentService;
    public void getMessage(){
        studentService.getMessage();
    }
}

③ 自由装配

给@Autowired注解设置required = false属性表示:能装就装,装不上就不装。

@Autowired(required = false)

三、完全注解开发

完全注解开发,是完全舍弃XML配置文件,全面使用注解来完成主要的配置。

1. 使用配置类取代配置文件

① 创建配置类

使用@Configuration注解将一个普通的类标记为Spring的配置类。

package com.zengchuiyu.ioc.configuration;

import org.springframework.context.annotation.Configuration;

/**
 * @author zengchuiyu
 * @create 2021-10-13 23:24
 */
@Configuration
public class OneConfiguration {
}

② 根据配置类创建IOC容器对象

private ApplicationContext contextAnno =
            new AnnotationConfigApplicationContext(OneConfiguration.class);
  • AnnotationConfigApplicationContext根据配置类创建IOC容器对象

2. 在配置类中配置bean

@Configuration
public class OneConfiguration {

    @Bean
    public OneComponent getComponent(){
        OneComponent oneComponent = new OneComponent();
        oneComponent.setComponentName("zengchuiyu");
        return oneComponent;
    }

}
  • @Bean注解相当于XML配置文件中的bean标签
  • @Bean注解标记的方法的返回值会被放入IOC容器

3. 在配置类中配置自动扫描的包

使用@ComponentScan注解

@Configuration
@ComponentScan("com.zengchuiyu.ioc.component")
public class OneConfiguration {

取消在OneComponent类上的注解配置,进行测试

 @Test
    public void test2(){
        OneComponent bean = contextAnno.getBean(OneComponent.class);
        String componentName = bean.getComponentName();
        System.out.println(componentName);
    }

在这里插入图片描述
成功!

四、整合junit4

1. 整合的介绍

通过整合junit4我们再也不需要自己创建IOC容器对象了
而且任何需要的bean都可以在测试类中直接享受自动装配

2. 操作

① 加入依赖

<!-- Spring的测试包 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.1</version>
</dependency>

② 创建测试类

/**
 * @author zengchuiyu
 * @create 2021-10-13 23:38
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:applicationContext.xml"})
public class Junit4Test {
    @Autowired
    private StudentController controller;
    @Test
    public void test1(){
        System.out.println(controller);
    }
}
  • junit的@RunWith注解:指定Spring为Junit提供的运行器
  • Spring的@ContextConfiguration指定Spring配置文件的位置

在这里插入图片描述
测试成功!

好东西嘿嘿

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring中,我们可以使用注解来配置和装配Bean,这可以使我们的代码更加简洁和易于维护。下面是关于如何基于注解配置和装配Bean的一些简要介绍: 1. 基于注解配置Bean 在Spring中,我们可以使用以下注解来配置Bean: - @Component:表示该类是一个Spring Bean,需要被Spring容器管理。 - @Service:表示该类是一个服务层的Bean。 - @Controller:表示该类是一个控制层的Bean。 - @Repository:表示该类是一个数据访问层的Bean。 这些注解都是基于@Component注解的衍生注解,它们的作用是更加明确地表示Bean的角色。我们可以在Bean类上添加这些注解,告诉Spring容器该类需要被管理。例如: ``` @Service public class UserService { // ... } ``` 2. 基于注解装配Bean 在Spring中,我们可以使用以下注解来装配Bean: - @Autowired:自动装配Bean。 - @Qualifier:指定具体的Bean名称进行装配。 - @Resource:指定具体的Bean名称进行装配,与@Qualifier类似。 - @Value:注入一个具体的值。 使用@Autowired注解进行自动装配时,Spring会自动在容器中寻找与该类型匹配的Bean,并将其注入到类的属性中。例如: ``` @Service public class UserService { @Autowired private UserDao userDao; // ... } ``` 使用@Qualifier或@Resource注解可以指定具体的Bean名称进行装配。例如: ``` @Service public class UserService { @Autowired @Qualifier("userDaoImpl") private UserDao userDao; // ... } ``` 使用@Value注解可以注入一个具体的值。例如: ``` @Service public class UserService { @Value("10") private int maxCount; // ... } ``` 以上就是关于Spring中基于注解配置和装配Bean的简要介绍,希望能对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值