Spring中Bean对象的存储和获取

目录

  • 1. 更简单的将bean存储到spring中
    • 1.0 前置工作,在配置文件中设置bean扫描的根路径
    • 1.1 通过注解将bean存储到spring中
      • 1.1.1 @Controller【控制器】
      • 关于类注解的bean的名称规则:
      • 1.1.2 @Service【服务】
      • 1.1.3@Repository【仓库】
      • 1.1.4@Component【组件】
      • 1.1.5 @Configuration【配置】
    • 1.2 为什么要这么多类注解?
    • 1.3.方法注解:@Bean
      • 1.3.1 方法注解要配合类注解使用
      • 1.3.2 重命名bean
  • 2.获取 Bean 对象(对象装配)
    • 2.1 属性注入
    • 2.2 构造方法注入
    • 2.3 Setter 注入
    • 2.4 三种注入优缺点分析
    • 2.5 @Resource:另一种注入关键字
    • 2.6@Autowired 和 @Resource 的区别
    • 2.7 同一类型多个 @Bean 报错
  • 3.总结

1. 更简单的将bean存储到spring中

1.0 前置工作,在配置文件中设置bean扫描的根路径

在这里插入图片描述

1.1 通过注解将bean存储到spring中

想要将对象存储在 Spring 中,有两种注解类型可以实现:
1.类注解:@Controller【控制器】、@Service【服务】、@Repository【仓库】、@Component【组件】、@Configuration【配置】。
2.方法注解:@Bean。
接下来我们分别来看。

1.1.1 @Controller【控制器】

Spring中Bean对象的存储和获取_第1张图片

package com.beans;
import org.springframework.stereotype.Controller;
@Controller//将当前对象存储到spring中
public class UserController {
    public void sayHi(String name){
        System.out.println("你好,"+name);
    }
}

使用之前读取对象的方式来读取上面的 UserController 对象:

import com.beans.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1.获取 spring 上下文
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        // 2.得到 bean
        UserController userController = context.getBean(UserController.class);
        // 3.使用 bean
        userController.sayHi("极致千叶");
    }
}

运行结果:
Spring中Bean对象的存储和获取_第2张图片

注意事项1:即使在spring配置文件中配置了bean的扫描路径,但是5大类注解是不能省略的。
注意事项2:即使加了5大类注解,但类没有放在spring配置的bean路径下,那么也是不能将类注入到spring中的。

关于类注解的bean的名称规则:

通常情况下‘是小驼峰(也就是将类名小写)就可以获取到bean对象

UserService userService=context.getBean("userService",UserService.class);
userService.sayHi("慕远笙歌");

如果第一个字母为大写,第二个字母为小写的情况下,那么bean的命名规则就是首字母小写
如果第一个和第二个字母都是大写的情况下,那么bean命名规则是原类名

1.1.2 @Service【服务】

package com.beans;

import org.springframework.stereotype.Service;
@Service//将当前对象存储到spring中
public class UserService {
        public void sayHi(String name) {
            System.out.println("你好," + name);
        }
}
import com.beans.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1.获取 spring 上下文
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        UserService userService=context.getBean("userService",UserService.class);
        userService.sayHi("慕远笙歌");
    }
}

1.1.3@Repository【仓库】

package com.beans;

import org.springframework.stereotype.Repository;

@Repository//将当前对象存储到spring中
public class UserRepository {
    public void sayHi(String name) {
        System.out.println("你好," + name);
    }
}

import com.beans.UserRepository;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1.获取 spring 上下文
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        UserRepository userRepository=context.getBean("userRepository", UserRepository.class);
        userRepository.sayHi("谋长节短");
    }
}

1.1.4@Component【组件】

package com.beans;

import org.springframework.stereotype.Component;

@Component//将当前对象存储到spring中
public class UserComponent {
    public void sayHi(String name) {
        System.out.println("你好," + name);
    }
}

import com.beans.UserComponent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1.获取 spring 上下文
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");


        UserComponent userComponent=context.getBean("userComponent",UserComponent.class);
        userComponent.sayHi("百战百胜");
    }
}

1.1.5 @Configuration【配置】

package com.beans;

import org.springframework.context.annotation.Configuration;

@Configuration//将当前对象存储到spring中
public class UserConfiguration {
    public void sayHi(String name) {
        System.out.println("你好," + name);
    }
}

import com.beans.UserConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1.获取 spring 上下文
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        UserConfiguration userConfiguration=context.getBean("userConfiguration",UserConfiguration.class);
        userConfiguration.sayHi("难知如阴");
    }
}

1.2 为什么要这么多类注解?

  1. @Component【组件】是其他四个注解的父类;
  2. Spring中Bean对象的存储和获取_第3张图片
    @Controller:表示的是业务逻辑层(控制器,和前端打交道【验证前端的有效性】);
    @Servie:服务层(组织数据调用相应的接口);
    @Repository:持久层(数据持久层【dao/repository】,和数据库直接打交道,执行具体的CRUD操作);
    @Configuration:配置层(存放所有的配置信息)。

1.3.方法注解:@Bean

类注解是添加到某个类上的,而方法注解是放到某个方法上的。

1.3.1 方法注解要配合类注解使用

在 Spring 框架的设计中,方法注解 @Bean 要配合类注解才能将对象正常的存储到 Spring 容器中,如下代码所示:

package com.beans;

import com.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;

@Controller
public class UserBeans {

    @Bean//将当前方法返回的对象存储到spring中,默认bean名称为方法名
    public User user1(){
        User user=new User();
        user.setId(1);
        user.setName("极致千叶");
        user.setPassword("123");
        return user;
    }
}

1.3.2 重命名bean

可以通过设置 name 属性给 Bean 对象进行重命名操作

package com.beans;

import com.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;

@Controller
public class UserBeans {
//给当前对象起一个别名
    @Bean(name="user2")//将当前方法返回的对象存储到spring中,默认bean名称为方法名
    public User user1(){
        User user=new User();
        user.setId(1);
        user.setName("极致千叶");
        user.setPassword("123");
        return user;
    }
}

这个重命名的 name 其实是一个数组,一个 bean 可以有多个名字:

package com.beans;

import com.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;

@Controller
public class UserBeans {
//给当前对象起一个或多个别名
    @Bean(name={"user2","user"})//将当前方法返回的对象存储到spring中,默认bean名称为方法名
    public User user1(){
        User user=new User();
        user.setId(1);
        user.setName("极致千叶");
        user.setPassword("123");
        return user;
    }
}

并且 name={} 可以省略,如下代码所示:

package com.beans;

import com.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;

@Controller
public class UserBeans {

    @Bean({"user2","user"})//将当前方法返回的对象存储到spring中,默认bean名称为方法名
    public User user1(){
        User user=new User();
        user.setId(1);
        user.setName("极致千叶");
        user.setPassword("123");
        return user;
    }
}

@Bean重命名后,使用方法名不能获取到Bean对象!!!如果没有对Bean进行重命名,那么可以使用方法名获取Bean对象

2.获取 Bean 对象(对象装配)

获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注入
对象装配(对象注入)的实现方法以下 3 种:

  1. 属性注入
  2. 构造方法注入
  3. Setter 注入
    接下来,我们分别来看。
    下面我们按照实际开发中的模式,将 Service 类注入到 Controller 类中。

2.1 属性注入

属性注入是使用 @Autowired 实现的,将 Service 类注入到 Controller 类中。
Service 类的实现代码如下:

package com.beans;

import com.model.User;
import org.springframework.stereotype.Service;
@Service//将当前对象存储到spring中
public class UserService {
    /**
     * 根据id获取用户
     * @param id
     * @return
     */
    public User getUserById(int id){
            //伪代码
            User user=new User();
            user.setId(id);
            user.setName("刑天");
            user.setPassword("123");
            return user;
        }
}

Controller 类的实现代码如下:

package com.beans;

import com.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller//将当前对象存储到spring中
public class UserController {
    //1.属性注入
    @Autowired
    private UserService userService;

    public User getUserById(Integer id){
        return userService.getUserById(id);
    }
}

App方法:

import com.beans.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.beans.Introspector;

public class App {
    public static void main(String[] args) {
        // 1.获取 spring 上下文
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        UserController userController=context.getBean(UserController.class);
        System.out.println(userController.getUserById(10));

    }
}

2.2 构造方法注入

构造方法注入是在类的构造方法中实现注入,如下代码所示:

package com.beans;

import com.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller//将当前对象存储到spring中
public class UserController2 {
    private UserService userService;
    //1.构造方法注入
    @Autowired//如果当前类只有一个构造方法,那么@Autowired可以省略
    public UserController2(UserService userService){
        this.userService=userService;
    }
    
    public void sayHi(String name){
        System.out.println("你好,"+name);
    }

    public User getUserById(Integer id){
        return userService.getUserById(id);
    }
}

如果当前类只有一个构造方法,那么@Autowired可以省略;但是如果当前方法中存在多个构造方法,那么@Autowired是不能省略的。

2.3 Setter 注入

Setter 注入和属性的 Setter 方法实现类似,只不过在设置 set 方法的时候需要加上 @Autowired 注解,如下代码所示:

package com.beans;

import com.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller//将当前对象存储到spring中
public class UserController3 {
    private UserService userService;
    //3.Setter 注入
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void sayHi(String name){
        System.out.println("你好,"+name);
    }

    public User getUserById(Integer id){
        return userService.getUserById(id);
    }
}

2.4 三种注入优缺点分析

  1. 属性注入的优点是简洁,使用方便;缺点是不通用,只能用于 IoC 容器,如果是非 IoC 容器不可用,并且只有在使用的时候会出现空指针异常。
  2. 构造方法注入是 Spring 推荐的注入方式,它的缺点是可能存在多个参数来实现构造方法的初始化,会显得比较臃肿,但出现这种情况你应该考虑一下当前类是否符合程序的单一职责的设计模式了,它的优点是通用性,并且能保证再调用对象之前,此对象一定存在。
  3. Setter 方式是 Spring 前期版本推荐的注入方式,但通用性不如构造方法,所有 Spring 现版本已经推荐使用构造方法注入的方式来进行类注入了。

2.5 @Resource:另一种注入关键字

在进行类注入时,除了可以使用 @Autowired 关键字之外,我们还可以使用 @Resource 进行注入,如下代码所示:

package com.beans;

import com.model.User;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller//将当前对象存储到spring中
public class UserController5 {
    @Resource
    private UserService userService;

   // @Resource
    public UserController5(UserService userService){
        this.userService=userService;
    }

    public User getUserById(Integer id){
        return userService.getUserById(id);
    }
}

2.6@Autowired 和 @Resource 的区别

出身不同:@Autowired 来自于 Spring,而 @Resource 来自于 JDK 的注解;

使用时设置的参数不同:相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如 name设置,根据名称获取 Bean。

支持的注入类型不同:@Autowired 支持属性注入、构造方法注入 和Setter 注入,@Resource 支持属性注入和 Setter 注入,不支持构造方法注入。

2.7 同一类型多个 @Bean 报错

一个类型被注册到Spring多次时,程序运行就会出现异常。

package com.beans;

import com.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;

@Controller
public class UserBeans {

//    @Bean("user2")//将当前方法返回的对象存储到spring中,默认bean名称为方法名
    @Bean(name="user1")
    public User user1(){
        User user=new User();
        user.setId(1);
        user.setName("极致千叶");
        user.setPassword("123");
        return user;
    }

    @Bean(name="user2")
    public User user2(){
        User user=new User();
        user.setId(2);
        user.setName("慕远笙歌");
        user.setPassword("456");
        return user;
    }
}

解决异常的办法:

  1. 使用正确的bean name。
  2. 设置bean name
  3. 使用@Autowired+@Qualifier
    ① 使用 @Resource(name=“XXX”)
package com.beans;

import com.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller
public class UserController6 {
    @Resource(name="user1")
    private User user;
    public void saiHi(){
        System.out.println(user);
    }
}

② 使用 @Qualifier(" ")

package com.beans;

import com.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller
public class UserController6 {
    @Autowired
    @Qualifier(value ="user2")
    private User user;

    public void saiHi(){
        System.out.println(user);
    }
}

3.总结

  1. 将对象存储在Spring中:
  • a.实用类注解:@Controller【控制器】、@Service【服务】、@Repository【仓库】、@Component【组件】、@Configuration【配置】,【它们之间的关系】
  • b.使用方法注解:@Bean【注意事项:必须配合类注解一起使用】
  1. Bean的命名规则:首字母和第二个字母都非大写,首字母小写来获取Bean,如果首字母和第二个字母都是大写,那么直接使用原Bean名来获取Bean。
  2. 从Spring中获取对象:
  • a.属性注入
  • b.Setter注入
  • c.构造函数注入(推荐)
  1. 注入的关键字有:
  • a.@Autowired
  • b.@Resource
  1. @Autowired和@Resource的区别:出身不同;使用时设置参数不同,@Resource支持更多的参数,比如name。
  2. 解决同一类型多个Bean的报错:
  • a.使用 @Resource(name=“XXX”)
  • b. 使用 @Qualifier(" ")
  • c.构造函数注入(推荐)

你可能感兴趣的:(Spring,spring,java,后端)