• Spring更简单的存储和读取Bean


    在这里插入图片描述

    请添加图片描述

    ⭐️前言⭐️

    在上一篇文章【Spring的创建与使用】中,我们已经了解了Spring中bean对象的基本的创建和使用方法,这篇文章通过注解的方法,使得存储和读取对象更加简单。

    🍉博客主页: 🍁【如风暖阳】🍁
    🍉精品Java专栏【JavaSE】【备战蓝桥】、【JavaEE初阶】【MySQL】【数据结构】
    🍉欢迎点赞 👍 收藏留言评论 📝私信必回哟😁

    🍉本文由 【如风暖阳】 原创,首发于 CSDN🙉

    🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言

    🍉博客中涉及源码及博主日常练习代码均已上传码云(gitee)GitHub


    请添加图片描述

    请添加图片描述

    🍅1.存储Bean

    简单的将Bean存储到容器,有以下几种方法:

    a)使用5大类注解实现
    b)通过@Bean方法注解

    下标我们一起来看具体的实现方式。

    1.1 前置工作

    在使用更简单的方法存储和读取bean对象之前,先完成前置工作——在Spring配置文件中设置bean的扫描根路径:

    
    <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="">content:component-scan>
    beans>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    1.2 使用5大类注解实现存储

    1.2.1 @Controller(控制器存储)

    使⽤ @Controller 存储 bean 的代码如下所示:

    @Controller
    public class UserController {
        public void sayHi() {
            System.out.println("你好,Contorller");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    我们先使⽤之前读取对象的⽅式来读取上⾯的 UserController 对象,如下代码所示:

    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",UserController.class);
            //3.使用bean
            userController.sayHi();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    此处我们的beanName依旧是类名的小驼峰命名法,在后边我们会具体讲述Spring使用五大类注解生成beanName的问题。

    1.2.2 @Service(服务存储)

    使⽤ @Service 存储 bean 的代码如下所示:

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

    读取bean的代码:

    public class App {
        public static void main(String[] args) {
            //1.得到Spring上下文
            ApplicationContext context=
                    new ClassPathXmlApplicationContext("spring-config.xml");
            //2.得到bean
            UserService userService=context.getBean("userService",UserService.class);
            //3.使用bean
            userService.sayHi();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    1.2.3 @Repository(仓库存储)

    使⽤ @Repository 存储 bean 的代码如下所示:

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

    读取 bean 的代码:

    public class App {
        public static void main(String[] args) {
            //1.得到Spring上下文
            ApplicationContext context=
                    new ClassPathXmlApplicationContext("spring-config.xml");
            //2.得到bean
            UserRepository userRepository=context.getBean("userRepository",UserRepository.class);
            //3.使用bean
            userRepository.sayHi();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    1.2.4 @Component(组件存储)

    使⽤ @Component 存储 bean 的代码如下所示:

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

    读取 bean 的代码:

    public class App {
        public static void main(String[] args) {
            //1.得到Spring上下文
            ApplicationContext context=
                    new ClassPathXmlApplicationContext("spring-config.xml");
            //2.得到bean
            UserComponent userComponent=context.getBean("userComponent",UserComponent.class);
            //3.使用bean
            userComponent.sayHi();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    1.2.5 @Configuration(配置存储)

    使⽤ @Configuration 存储 bean 的代码如下所示:

    @Configuration
    public class UserConfiguration {
        public void sayHi() {
            System.out.println("你好,Configuration");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    读取 bean 的代码:

    public class App {
        public static void main(String[] args) {
            //1.得到Spring上下文
            ApplicationContext context=
                    new ClassPathXmlApplicationContext("spring-config.xml");
            //2.得到bean
            UserConfiguration userConfiguration=context.getBean("userConfiguration",UserConfiguration.class);
            //3.使用bean
            userConfiguration.sayHi();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    1.3 为什么需要这么多的注解?

    既然上述的五大类注解都能够完成将Bean对象存储到Spring中的功能,那为什么需要这么多的注解呢?

    这是因为不同的注解有不同的用途,在程序猿看到类注解后,就能直接了解当前类的用途,增加了代码的可读性

    程序的工程分层,调用流程如下:
    在这里插入图片描述

    1.4 五大类注解之间的关系

    查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:
    在这里插入图片描述
    这些注解里都有一个注解@Component,说明它们本身就是属于@Component的“子类”。

    1.5 Spring使用五大类注解生成beanName

    在1.2所有的获取bean对象的方法中,使用到的beanName都是小驼峰命名,但如果出现以下bean,还能通过小驼峰获取到吗?

    @Controller
    public class APIController {
        public void sayHi() {
            System.out.println("你好,APIController");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    在我们去还以小驼峰命名法去获取bean对象时,发现报错,说明并不是所有的beanName都是以小驼峰命名法来命名的。

    我们来查看beanName的命名规则源码:
    (关于注解beanName的生成器)
    在这里插入图片描述
    我们来看bean对象的命名规则的方法:
    在这里插入图片描述
    它使⽤的是 JDK Introspector 中的 decapitalize ⽅法,源码如下:

    public static String decapitalize(String name) {
    	 if (name == null || name.length() == 0) {
    	 	return name;
    	 }
    	 // 如果第⼀个字⺟和第⼆个字⺟都为⼤写的情况,是把 bean 的⾸字⺟也⼤写存储了
    	 if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
    		 Character.isUpperCase(name.charAt(0))){
    	 	return name;
    	 }
    	 // 否则就将⾸字⺟⼩写
    	 char chars[] = name.toCharArray();
    	 chars[0] = Character.toLowerCase(chars[0]);
    	 return new String(chars);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    如果第⼀个字母和第⼆个字母都为⼤写的情况,是把 bean 的⾸字母也⼤写存储了,否则就将⾸字母⼩写

    所以对于上⾯报错的代码,我们只要改为以下代码就可以正常运⾏了:
    在这里插入图片描述

    1.6 通过@Bean方法注解实现存储

    类注解是添加到某个类上的,而方法注解是放到某个方法上的,但仅依靠方法注解是仍然获取不到bean的,还需要搭配类注解:

    1.6.1 方法注解要搭配类注解使用

    先完成类代码:

    public class User {
        private int id;
        private String name;
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    '}';
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    @Component
    public class UserBeans {
        @Bean
        public User getUser() {
            User user=new User();
            user.setId(1);
            user.setName("张三");
            return user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用User类:
    在这里插入图片描述
    我们发现这样也可以获得User对象,但是beanName很别扭(也可以只通过bean type来获取该类,但如果出现多次存储的情况就会报错),因为是方法名,而不是类名的小驼峰,所以我们可以通过设置name属性给Bean对象,进行重命名操作,下边看具体演示:

    1.6.2 重命名Bean

    可以通过设置name属性给Bean对象进行重命名操作,如下代码所示:

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

    此时我们使用u1就可以获取到User对象了,如下代码所示:
    在这里插入图片描述

    🍅2.获取Bean

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

    对象装配(对象注入)的实现方法有以下三种:

    • 属性注入
    • 构造方法注入
    • Setter注入

    下边我们按照实际开发中的模式,将Service类注入到Controller类中。

    2.1 属性注入

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

    Service类的实现代码如下:

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

    Controller类的实现代码如下:

    @Controller
    public class UserController2 {
        //属性注入
        @Autowired
        private UserService userService;
    
        public void sayHi() {
            userService.sayHi();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    获取 Controller 中的 sayHi⽅法:

    在这里插入图片描述

    2.2 构造方法注入

    构造方法注入是在类的构造方法上,使用@Autowired实现注入,如下代码所示:

    @Controller
    public class UserController3 {
        private UserService userService;
    
        //构造方法注入
        @Autowired
        public UserController3(UserService userService) {
            this.userService = userService;
        }
        
        public void sayHi() {
            userService.sayHi();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    注意
    如果只有一个构造方法,那么@Autowired注释可以省略,但如果类中有多个构造方法,就必须加上注解来明确指定到底使用哪个构造方法,否则会报错。

    2.3 Setter注入

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

    @Controller
    public class UserController4 {
        private UserService userService;
        
        //Setter注入
        @Autowired
        public void setUserService(UserService userService) {
            this.userService=userService;
        }
        
        public void sayHi() {
            userService.sayHi();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.4 三种注入方式的区别

    • 属性注入:写法简单,但是通用性不好,它只能运行在IoC容器下,如果是非IoC容器就会出现问题。
    • Setter注入:该注入方式是早期Spring版本推荐的方式,但Setter注入的通用性没有构造方法注入的通用性好。
    • 构造方法注入:通用性更好,它能确保在使用注入对象之前,此注入对象一定初始化过了。当构造方法参数较多时,开发者就要检查自己所写的代码是否符合单一设计原则的规范了,此注入方式也是Spring后期版本中推荐的注入方式

    2.5 另一种注入注解@Resourse

    该注入注解与@Autowired功能几乎相同,但也有差别,下边看两者的具体差别:

    1、出身不同:@Resourse来自于JDK,而@Autowired是Spring框架提供的。
    2、用法不同:@Autowired支持属性注入、构造方法注入和Setter注入,而@Resourse比前者少一个,它不支持构造方法注入。
    3、支持的参数不同:@Resourse支持更多的参数设置,比如nametype设置,而@Autowired只支持required参数设置。

    2.6 同一个类型多个@Bean报错

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

    @Component
    public class UserBeans {
        @Bean(name="u1")
        public User getUser1() {
            User user=new User();
            user.setId(1);
            user.setName("张三");
            return user;
        }
        @Bean(name="u2")
        public User getUser2() {
            User user=new User();
            user.setId(2);
            user.setName("李四");
            return user;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在另一个类中获取User对象,如下代码所示:

    @Controller
    public class UserController {
        @Resource
        private User user;
    
        public void sayHi() {
            System.out.println("user->"+user);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行结果如下:
    在这里插入图片描述
    报错的原因是非唯一的Bean对象。

    同一个类型多个Bean的报错处理有以下三种方式

    1、精确地描述bean的名称(将注入的名称写对)
    在这里插入图片描述
    2、使用@Resourse设置name的方式来重命名注入对象
    在这里插入图片描述
    3、使用@Autowired+@Qualifier来筛选bean对象
    在这里插入图片描述

    🍅3.总结

    1、将对象存储到Spring中:

    • 使用类注解:@Controller@Service@Repository@Configuration@Component【了解它们之间的关系与区别】
    • 使用方法注解:@Bean【注意搭配类注解一起使用】

    2、Bean的命名规则:
    首字母和第二个字母都是大写,那么直接使用原Bean名来获取Bean,否则就让首字母小写(小驼峰)来获取Bean。

    3、从Spring中获取对象:

    • 属性注入
    • Setter注入
    • 构造函数注入(官方推荐)

    4、注入的关键字:

    • @Autowired
    • @Resourse

    5、 @Autowired@Resourse的区别:

    • 出身不同
    • @Resourse不支持构造方法注入
    • @Resourse支持更多的参数

    6、解决同一类型多个Bean的报错:

    • 使用更精确的bean名称
    • 使用 @Resourse(name="")
    • 使用@Autowired @Qulifier("value =")

    ⭐️最后的话⭐️
    总结不易,希望uu们不要吝啬你们的👍哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正😁

    请添加图片描述

  • 相关阅读:
    Node.js精进(11)——Socket.IO
    RabbitMQ面试官这样问
    Android 11添加所有特许权限白名单
    Efficient Batched Oblivious PRF -Private Set Intersection
    JavaScript 中的判等
    Flex布局的三个属性要深刻理解!
    Linux:进程管理和调度
    模拟shell小程序
    【餐厅点餐平台|三】模块设计
    (Note)计算机专业术语 - Socket (套接字)
  • 原文地址:https://blog.csdn.net/qq_60856948/article/details/128181050