• 【Spring】更简单的读取和存储对象


    在 Spring 中想要更简单的存储和读取对象的核⼼是使⽤注解。

    一. 存储 Bean 对象

    之前我们存储 Bean 时,需要在 spring-config 中添加⼀⾏ bean 注册内容才⾏:
    在这里插入图片描述
    ⽽现在我们只需要⼀个注解就可以替代之前要写的⼀⾏配置,不过在开始存储对象之前,我们先要来点准备⼯作。

    1. 前置工作:配置扫描路径

    想要将对象成功的存储到 Spring 中,我们需要配置⼀下存储对象的扫描包路径,只有被配置的包下的所有类,添加了注解才能被正确的识别并保存到 Spring 中。

    在 spring-config.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:content="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 https://www.springframework.org/schema/context/spring-context.xsd">
        <content:component-scan base-package="com.demo.example"></content:component-scan>
    </beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    <content:component-scan base-package="com.demo.example"></content:component-scan>
    
    • 1

    上面这行代码指明了组件的扫描路径。即使添加了注解,如果不是在配置的扫描包下的类对象,也是不能被存储到 Spring 中的。

    2. 添加注解存储 Bean 对象

    想要将对象存储在 Spring 中,有两种注解类型可以实现:

    1. 类注解:@Controller、@Service、@Repository、@Component、@Configuration。
    2. ⽅法注解:@Bean。

    @Controller(控制器存储)

    @Controller // 将对象存储到 Spring 中
    public class UserController {
        public void sayHi(String name) {
            System.out.println("Hi," + name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    @Service(服务存储)

    @Service
    public class UserService {
        public void sayHi(String name) {
            System.out.println("Hi," + name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    @Repository(仓库存储)

    @Repository
    public class UserRepository {
        public void sayHi(String name) {
            System.out.println("Hi," + name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    @Component(组件存储)

    @Component
    public class UserComponent {
        public void sayHi(String name) {
            System.out.println("Hi," + name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    @Configuration(配置存储)

    @Configuration
    public class UserConfiguration {
        public void sayHi(String name) {
            System.out.println("Hi," + name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3. 为什么要这么多类注解?

    既然功能是⼀样的,为什么需要这么多的类注解呢?

    就是为了让程序员看到类注解之后,就能直接了解当前类的⽤途,⽐如:

    • @Controller:表示的是业务逻辑层;
    • @Servie:服务层;
    • @Repository:持久层;
    • @Configuration:配置层。

    程序的⼯程分层,调⽤流程如下:

    在这里插入图片描述

    类注解之间的关系

    查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:这些注解⾥⾯都有⼀个注解 @Component,说明它们本身就是属于 @Component 的 “子类”

    Bean 命名规则

    1. 对于类的第一个首字母大写,第二个小写,那么第一个首字母改为小写就是存到容器中的 Bean 的名字。

    @Component
    public class UserComponent {
        public void sayHi(String name) {
            System.out.println("Hi," + name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
            UserComponent userComponent = (UserComponent) context.getBean("userComponent");
    
    • 1

    2. 其他所有情况都是原 Bean 的名字

    @Component
    public class JDBC {
        public void sayHi(String name) {
            System.out.println("Hi," + name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    //        JDBC jdbc = (JDBC) context.getBean("jDBC"); // 获取不到
            JDBC jdbc = (JDBC) context.getBean("JDBC"); // 获取的到
    
    • 1
    • 2

    4. 方法注解 @Bean

    类注解是添加到某个类上的,⽽⽅法注解是放到某个⽅法上的

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

    public class Users {
        @Bean
        public User user1() {
            User user = new User();
            user.setId(1);
            user.setName("Java");
            return user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    只在方法上加 @Bean 注解是不起作用的, 要搭配类注解一起使用。

    @Component
    public class Users {
        @Bean
        public User user1() {
            User user = new User();
            user.setId(1);
            user.setName("Java");
            return user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    注意:获取 Bean 时使用对应的方法名获取

    User user = (User) context.getBean("user1");
    
    • 1

    重命名 Bean

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

    @Component
    public class Users {
        @Bean(name = {"u1"})
        public User user1() {
            User user = new User();
            user.setId(1);
            user.setName("Java");
            return user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    此时我们使⽤ u1 就可以获取到 User 对象了

            User user = (User) context.getBean("u1");
            System.out.println(user);
    
    • 1
    • 2

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

    @Component
    public class Users {
        @Bean(name = {"u1", "us1"})
        public User user1() {
            User user = new User();
            user.setId(1);
            user.setName("Java");
            return user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    并且 name={} 可以省略

        @Bean({"u1", "us1"})
        public User user1() {
            User user = new User();
            user.setId(1);
            user.setName("Java");
            return user;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注⼊。

    对象装配(对象注⼊)的实现⽅法以下 3 种:

    1. 属性注⼊
    2. 构造⽅法注⼊
    3. Setter 注⼊

    1. 属性注入

    举个栗子:使⽤ @Autowired 将 Service 类注⼊到 Controller 类中。

    @Controller
    public class UserController {
        // 注⼊⽅法1:属性注⼊
        @Autowired
        private UserService userService;
        
        public User getUser(Integer id) {
            // 注入之后直接就可以使用
            return userService.getUser(id);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2. 构造方法注入

    @Controller
    public class UserController2 {
        // 注⼊⽅法2:构造⽅法注⼊
        private UserService userService;
    
        @Autowired
        public UserController2(UserService userService) {
            this.userService = userService;
        }
        
        public User getUser(Integer id) {
            return userService.getUser(id);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    如果只有⼀个构造⽅法,那么 @Autowired 注解可以省略。

    @Controller
    public class UserController2 {
        // 注⼊⽅法2:构造⽅法注⼊
        private UserService userService;
        // 将 Autowired 省略了
        public UserController2(UserService userService) {
            this.userService = userService;
        }
        
        public User getUser(Integer id) {
            return userService.getUser(id);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    但是如果类中有多个构造⽅法,那么需要添加上 @Autowired 来明确指定到底使⽤哪个构造⽅法,否则程序会报错。

    3. Setter 注入

    Setter 注⼊和属性的 Setter ⽅法实现类似,只不过在设置 set ⽅法的时候需要加上 @Autowired 注解。

    @Controller
    public class UserController3 {
        // 注⼊⽅法3:Setter注⼊
        private UserService userService;
        @Autowired
        public void setUserService(UserService userService) {
            this.userService = userService;
        }
    
        public void getUser(Integer id) {
            userService.sayHi("hello");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4. 三种注入优缺点分析

    • 属性注⼊的优点是简洁,使⽤⽅便;
      缺点是只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,要是想自己 new 一下这个类的对象,那么相关的依赖无法完成注入。
      并且不能注入一个不可变的对象(一个 final 修饰的类),因为 Java 中一个 final 对象要么直接赋值要么在构造方法中赋值,不能注入。
      在这里插入图片描述

    • 构造⽅法注⼊是 Spring 推荐的注⼊⽅式,它的缺点是如果有多个注⼊会显得⽐较臃肿,它的优点
      可以注入不可变对象;
      注入的对象不可变,因为构造方法只随着累加载执行一次;
      通用性更好。

    • Setter ⽅式是 Spring 前期版本推荐的注⼊⽅式,但通⽤性不如构造⽅法,同样不能注入一个不可变的对象,同时注入的对象可以被修改,因为 Setter 注入只是使用一个普通的方法,其他类也可以多次调用这个方法。所以 Spring 现版本已经推荐使⽤构造⽅法注⼊的⽅式来进⾏类注⼊了。

    @Controller
    public class UserController3 {
        // 注⼊⽅法3:Setter注⼊
        private UserService userService;
        @Autowired
        public void setUserService1(UserService userService) {
            this.userService = userService;
        }
    
        public void getUser() {
            this.setUserService1(null);
            userService.sayHi("");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5. @Resource:另一种注入关键字

    在进⾏类注⼊时,除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊

    @Controller
    public class UserController {
        // 注⼊
        @Resource
        private UserService userService;
        public User getUser(Integer id) {
            return userService.getUser(id);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    @Autowired 和 @Resource 的区别

    • 出身不同:@Autowired 来⾃于 Spring,⽽ @Resource 来⾃于 JDK 的注解;
    • 使⽤时设置的参数不同:相⽐于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如name 设置,根据名称获取 Bean。
    • @Autowired 可⽤于 Setter 注⼊、构造函数注⼊和属性注⼊,⽽ @Resource 只能⽤于 Setter 注⼊和属性注⼊,不能⽤于构造函数注⼊。

    6. 同一类型多个 @Bean 报错

    当出现以下多个 Bean,返回同⼀对象类型时程序会报错,如下代码所示:

    @Component
    public class Users {
        @Bean
        public User user1() {
            User user = new User();
            user.setId(1);
            user.setName("Java");
            return user;
        }
        @Bean
        public User user2() {
            User user = new User();
            user.setId(2);
            user.setName("MySQL");
            return user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在另⼀个类中获取 User 对象

    @Controller
    public class UserController4 {
        // 注⼊
        @Resource
        private User user;
        public User getUser() {
            return user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    代码执行报错,报错的原因是,⾮唯⼀的 Bean 对象
    在这里插入图片描述

    解决同⼀个类型,多个 bean 的解决⽅案有以下两个:

    • 使⽤ @Resource(name=“user1”) 定义。
    • 使⽤ @Qualifier 注解定义名称。
    1. 使⽤ @Resource(name=“XXX”)
    @Controller
    class UserController4 {
        // 注⼊
        @Resource(name = "user1")
        private User user;
        public User getUser() {
            return user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 使⽤ @Qualifier
    @Controller
    public class UserController4 {
        // 注⼊
        @Autowired
        @Qualifier(value = "user2")
        private User user;
        public User getUser() {
            return user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    好啦! 以上就是对 Spring 更简单的读取和存储对象的讲解,希望能帮到你 !
    评论区欢迎指正 !

  • 相关阅读:
    Centos7安装nginx及网页如何放入nginx
    新超导光子电路
    day-3-2-3
    从智能锁谈STM32安全技术
    .NET Framework中自带的泛型委托Action
    Vue发布自定义组件库
    在找工作时的准备工作:结合现状,针对意向企业做好充分准备
    Windows 快捷方式
    Beego框架学习
    2022年0902Maven的继承和利用Idea创建Maven工程的内容<第五课>
  • 原文地址:https://blog.csdn.net/m0_61832361/article/details/133520199