通过之前的学习,我们也能够实现基本的 Spring 读取和存储对象操作,感觉有点麻烦,接下来, 更简单的存储和读取对象的核心就是使用注解

  • 1 存储 Bean 对象
    • 1.1 配置扫描路径(重要)
    • 1.2 添加注解存储 Bean 对象
      • 1.2.1 类注解
        • ① @Controller(控制器存储)
        • ② @Service(服务存储)
        • ③ @Repository(仓库存储)
        • ④ Configuration(配置存储)
        • ⑤ Component(组件存储)
        • 测试读取 bean 的代码
        • 注意事项
        • 为什么需要这么多类注解?
        • 类注解之间的关系
      • 1.2.2 @Bean(方法注解)
        • 方法重命名
  • 2. 获取 Bean 对象(对象装配)
    • 2.1 属性注入
    • 2.2 构造方法注入
    • 2.3 Setter注入
      • 三种注入优缺点分析
    • 2.4 @Resource: 另一种注入关键字
    • @Autowired 和 @Resource 的区别
    • 同一个类型多个 @Bean 报错

1 存储 Bean 对象

1.1 配置扫描路径(重要)

先把依赖文件导入pom.xml:

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.3.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.2.3.RELEASE</version></dependency></dependencies>

接下来写入配置文件,名字最好起的有意义

把这串类容粘贴进去:

<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="beans"></content:component-scan></beans>

1.2 添加注解存储 Bean 对象

有两种注解类型可以实现:

1: 使用 5 大类注解实现:@Controller[控制器],@Service[服务],@Repository[仓库],
@Configuration[配置],Component[组件]

2: 通过方法注解: @Bean方法

1.2.1 类注解

① @Controller(控制器存储)

import org.springframework.stereotype.Controller;@Controllerpublic class UserController {public void sayHi(String name){System.out.println("hello: "+name);}}


后面解释原因.

② @Service(服务存储)

import org.springframework.stereotype.Service;@Servicepublic class UserService {public void sayHi(String name){System.out.println("hello: "+name);}}

③ @Repository(仓库存储)

import org.springframework.stereotype.Repository;@Repositorypublic class UserRepository {public void sayHi(String name){System.out.println("hello: "+name);}}

④ Configuration(配置存储)

import org.springframework.context.annotation.Configuration;@Configurationpublic class UserConfiguration {public void sayHi(String name){System.out.println("hello: "+name);}}

⑤ Component(组件存储)

import org.springframework.stereotype.Component;@Componentpublic class UserComponent {public void sayHi(String name){System.out.println("hello: "+name);}}

测试读取 bean 的代码

import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");//ControllerUserController userController = context.getBean("userController",UserController.class);userController.sayHi("Controller");//ServiceUserService userService = context.getBean("userService",UserService.class);userService.sayHi("Service");//RepositoryUserRepository userRepository = context.getBean("userRepository",UserRepository.class);userRepository.sayHi("Repository");//ConfigurationUserConfiguration userConfiguration = context.getBean("userConfiguration",UserConfiguration.class);userConfiguration.sayHi("Configuration");//ComponentUserComponent userComponent = context.getBean("userComponent",UserComponent.class);userComponent.sayHi("Component");}}

注意事项

1: 读取存入对象的 id 默认情况首字母是要小写的,大写读不到

2: 当第一个字母和第二个字母都大写了,首字母小写就不能读到
这里就需要去观察源码是怎么实现的了,
双击shift搜索beanName

它使⽤的是 JDK Introspector 中的 decapitalize ⽅法,源码如下
像这种情况大写就行了

3: 包路径要写对

为什么需要这么多类注解” />

类注解之间的关系

查看 @Controller/@Service/@Repository/@Configuration等注解的源码发现:


这几个注解都有一个注解@Component,说明了它们本身就是属于@Component"子类"

1.2.2 @Bean(方法注解)

类注解是添加到某个类上的,⽽⽅法注解是放到某个⽅法上的,如以下代码的实现:
先创建一个User类:

public class User {private int id;private String name;@Overridepublic 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;}}

在创一个UserBean:

import org.springframework.context.annotation.Bean;import org.springframework.stereotype.Component;@Componentpublic class UserBean {@Beanpublic User user(){User user = new User();user.setId(1);user.setName("张三");return user;}}

测试读取的内容:

import beans.User;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");User user = context.getBean("user",User.class);System.out.println(user.toString());}}

注意要有类注解,不然获取不到:

如果不加类注解:

方法重命名

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

@Bean 命名规则,当没有设置 name 属性时,那么 bean 默认的名称就是方法名,当设置了name 属性之后,只能通过重命名的 name 属性对应的值来获取,也就是说重命名之后,在使用方法名就获取不到 bean 对象

他也可以重命名多个:

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

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

对象注入(对象装配)[从容器中将对象读取出来]三种方式:

  • 属性注入(字段注入)
  • 构造方法注入
  • Setter注入

2.1 属性注入

属性注入使用 @Autowired 实现的,我们来将 Service 类注入到 Controller 类中:
Service:

import org.springframework.stereotype.Service;@Servicepublic class UserService {public void sayHi(){System.out.println("hello,Service!");}}

Controller:

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;@Controllerpublic class UserController {@Autowiredprivate UserService userService;public void sayHi(){userService.sayHi();}}

App启动:

import beans.UserController;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class App2 {public static void main(String[] args) {ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");UserController userController = context.getBean(UserController.class);userController.sayHi();}}

2.2 构造方法注入

构造⽅法注⼊是在类的构造⽅法中实现注⼊

2.3 Setter注入

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

注:如果当前类里构造方法只有一个, 那么@Autowired是可以被省略的

三种注入优缺点分析

属性注入:
优点就是简洁,使用方便;
缺点通用性不好,只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空指针异常)

构造方法(官方推荐):
它的缺点是如果有多个注⼊会显得⽐较臃肿,但出现这种情况你应该考虑⼀下当前类是否符合程序的单⼀职责的设计模式了,它的优点是通⽤性好,在使⽤之前⼀定能把保证注⼊的类不为空

Setter注入:
Setter ⽅式是 Spring 前期版本推荐的注⼊⽅式,但通⽤性不如构造⽅法,所有 Spring 现版本已经推荐使⽤构造⽅法注⼊的⽅式来进⾏类注⼊了

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

在进⾏类注⼊时,除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊,注意一点的是,@Resource 无法进行构造方法注入

属性注入:

Setter注入:

构造方法注入就不行:

@Autowired 和 @Resource 的区别

1: 出身不同: @Resource 来自于 JDK(Java 亲儿子),@Autowired 是 Spring 框架提供的

2: 用法不同: @Autowired 支持属性注入,构造方法注入,Setter注入,而 @Resource 不支持构造方法注入

3: 支持的参数不同: @Resource 支持更多的参数设置,比如 name,type 设置,而@Autowired 只支持required 参数设置

同一个类型多个 @Bean 报错

报错的原因就是非唯一的 Bean 对象

解决办法:

1: 精确的描述 bean 的名称(将注入的名称写对)

2: 使用@Resource 设置 name 的方式 来重命名注入对象(如果已经写太多不想改了就可以用这种方式)
注: @Atowired不能这样设置

3: 使用 @Qualifier来筛选bean对象(@Atowired@Resource都可以)