SpringFrameWork之注解类管理Bean

1 Bean 注解方式的扫描

1.1 .1注解理解

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

1.1.2 扫描理解

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

使用注解方式:

(1):我们需要在ioc容器里添加的组件上添加上注解,该注解并不能执行,只是后来为了方便让ioc容器知道需要在ioc容器中添加上什么类。

(2):编写配置扫描信息,ioc容器并不是挨着扫描所有包的所有类,来看需要将哪个类添加在容器中,这样效率很慢,我们需要指定哪些包有需要添加的组件。

(3):创建容器....获取bean对象.

1.1.3 应用:

a.准备项目pom文件。


   
   
   
        org.springframework
        spring-context
        6.0.6
   

   
   
        org.junit.jupiter
        junit-jupiter-api
        5.3.1
   

b.准备组件类

普通组件

package com.cky;

import org.springframework.stereotype.Component;

@Component
public class Common {
}

Controller组件

package com.cky;

import org.springframework.stereotype.Controller;

@Controller
public class UserCon {
}

Service组件

package com.cky;

import org.springframework.stereotype.Service;

@Service
public class UserSerive {
}

Dao组件 

package com.cky;

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
}

c.编写配置文件




    
    
        
    
    
    
    





d.测试

public class testdemo {
    @Test
    public void test_01(){
        //实例化容器
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("demo01.xml");
        //得到Bean对象
        UserDao userDao=context.getBean("userDao",UserDao.class);
        System.out.println(userDao);
        UserSerive userSerive=context.getBean(UserSerive.class);
        System.out.println(userSerive);
    }
}

1.1.4 组件注解区别:

Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。 SpringFrameWork之注解类管理Bean_第1张图片

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

对于Spring使用IOC容器管理这些组件来说没有区别,也就是语法层面没有区别。所以@Controller、@Service、@Repository这三个注解只是给开发人员看的,让我们能够便于分辨组件的作用。

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

1.1.5 组件beanname 问题

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

默认情况:

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

但是,我们也可以使用value进行配置id

@Repository(value = "userdao")
public class UserDao {
}

1.1.6 总结:

1. 注解方式IoC只是标记哪些类要被Spring管理
2. 最终,我们还需要XML方式或者后面讲解Java配置类方式指定注解生效的包
3. **现阶段配置方式为 注解 (标记)+ XML(扫描)**

2、扩展周期方法和作用域

至于周期方法和作用域具体是什么,可见文章1,在这里不重复介绍。

使用注解的方式来编写周期方法:

A.周期方法声明

public class BeanOne {

  //周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
  @PostConstruct  //注解制指定初始化方法
  public void init() {
    // 初始化逻辑
  }
}

public class BeanTwo {
  
  @PreDestroy //注解指定销毁方法
  public void cleanup() {
    // 释放资源逻辑
  }
}

B.组件作用域配置

@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) //单例,默认值
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //多例  二选一

public class BeanOne {

  //周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
  @PostConstruct  //注解制指定初始化方法
  public void init() {
    // 初始化逻辑
  }
}

注意:单例的话会在容器关闭的时候进行销毁工作,但是多例不会。 

3、Bean属性赋值:引用类型自动配置(DI)

3.1 场景及实例:

UserController 需要 UserService

UserService需要UserDao

a. 准备组件 并在组件中配置 IOC 和DI

package demo03;

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
    public void show2(){
        System.out.println("Userdao");
    }
}
package demo03;

import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserService {
//    @Autowired
//    @Qualifier(value ="userdao")
    @Resource(name = "userdao")
    private UserDao userDao;
    public void show1(){
        userDao.show2();
        System.out.println("UserService");
    }
}
package demo03;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    @Autowired
    private UserService userService;
    public void show(){
        userService.show1();
        System.out.println("usercontroller");
    }
}

b.编写配置文件 确定扫描哪写包



c.编写测试代码:

    @Test
    public void test_03(){
        //实例化容器
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("demo03.xml");
        //得到Bean对象
        UserController userController=context.getBean(UserController.class);
        userController.show();

}

d.结果:

SpringFrameWork之注解类管理Bean_第2张图片

3.2 对实例讲解

3.2.1 @Autowired 注解

在使用注解方式时,我们没必要像 XML方式那样,在组件中写上setter,使用之后使用配置的方式进行DI配置。只需要在成员变量上加上@Autowired注解即可,不需要提供setXxx()方法。以后我们在项目中的正式用法就是这样。

A.该注解可添加在成员变量上(最常用)

@Service("smallDog")
public class SoldierService {
    
    @Autowired
    private SoldierDao soldierDao;
    
    public void getMessage() {
        soldierDao.getMessage();
    }
}

B. 构造方法上

@Controller(value = "tianDog")
public class SoldierController {
    
    private SoldierService soldierService;
    
    @Autowired
    public SoldierController(SoldierService soldierService) {
        this.soldierService = soldierService;
    }
    ……

C. Set方法上

@Controller(value = "tianDog")
public class SoldierController {

    private SoldierService soldierService;

    @Autowired
    public void setSoldierService(SoldierService soldierService) {
        this.soldierService = soldierService;
    }
    ……

3.2.2 工作流程

SpringFrameWork之注解类管理Bean_第3张图片

- 首先根据所需要的组件类型到 IOC 容器中查找
    - 能够找到唯一的 bean:直接执行装配
    - 如果完全找不到匹配这个类型的 bean:装配失败
    - 和所需类型匹配的 bean 不止一个
        - 没有 @Qualifier 注解:根据 @Autowired 标记位置成员变量的变量名作为 bean 的 id 进行匹配
            - 能够找到:执行装配
            - 找不到:装配失败
        - 使用 @Qualifier 注解:根据 @Qualifier 注解中指定的名称作为 bean 的id进行匹配
            - 能够找到:执行装配
            - 找不到:装配失败 

只有一个bean的我们不讨论,这里仅需要根据类型需查找ioc中是否有该组件类型即可。

下边讨论一下不止一个bean。

比如一个接口,我们的两个类都实现了该接口。那么这两个类与该接口 的instanceof 都为true。

在我们在其它组件中注入该接口时,ioc容器会发现有两个类 都是该接口的实例化组件,此时就会报错,解决方法①:我们可以使用bean id的方式来找到其中一个实例化组件,就是在编写该接口变量时,接口变量的名字写成其中一个组件的id,那么就会根据该id确定其中的一个实例化组件。

方法②:我们可以 在该接口变量的上方,通过@Autowried@Qualifier注解,在后者里边添加上value属性,即我们要选用实例化组件的id。

方法③:我们可以使用@Resource 注解,不过该注解是java的一种规范化技术,

我们在使用该注解时,需要导入依赖


    jakarta.annotation
    jakarta.annotation-api
    2.1.1

3.2.3 @Resource与@Autowried 区别

@Resource注解也可以完成属性注入。那它和@Autowired注解有什么区别?

- @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
- @Autowired注解是Spring框架自己的。
- **@Resource注解默认根据Bean名称装配,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型装配。**
- @Autowired注解默认根据类型装配,如果想根据名称装配,需要配合@Qualifier注解一起用。
- @Resource注解用在属性上、setter方法上。
- @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。

总结:

(1)@Autowired注解默认根据类型装配,如果类型没有,则报错。如果想根据名称装配,需要配合@Qualifier注解一起用。一旦使用名称来装配,即使类型有,但是名称不匹配也会报错。

(2)@Resource注解默认根据Bean名称装配,如果Bean名称找不到,则会启动根据类型来装配。如果指定了名称,类型有但是名称不匹配就会报错。如果没有启动名称匹配,则后续会在进行类型匹配。

4、使用@Value注解

对于基本数据类型的DI

对于基本数据类型

我们可以直接赋值的方式

比如

private int age=8;

同时我们也可以使用@Value注解 这个注解主要是为了配置外部属性

a.配置组件

package demo04;
 @Service 
public class JavaBean 
{ private int age=8; 
 @Value("${url}") 
private String url; 
 @Value("${a:cui}") 冒号后边是默认值,即配置中如果没有a属性的话,就自动赋值为冒号后边的值。 
private String name;
 @Override public String toString() 
{ return "JavaBean{" + "age=" + age + ", url='" + url + '\'' + ", name='" + name + '\'' + '}'; } }


b. 配置信息 demo04.xml


// 扫描的包


//把配置的包导入进来,之后在该容器中的组件都可以通过{$xxx}来访问xxx属性名的值

c.一些外部配置文件 aoo,properties

SpringFrameWork之注解类管理Bean_第4张图片

 5、总结:

基于注解的方式,我们还是需要xml配置文件

xml配置:①扫描包的配置 ②外部配置包的部署 ③第三方组件 如jdbctemplate等

之后我们将学习配置类的方式,使用上配置类我们就可以不用在使用xml的方式来完成上边三种配置了。

你可能感兴趣的:(java,spring,java,开发语言)