4.Spring更简单的读取和存储对象

发布于:2023-01-21 ⋅ 阅读:(461) ⋅ 点赞:(0)

1.存储 Bean 对象

之前我们存储 Bean 时, 需要在 Spring-config 中添加 一行 bean 注册内容才行,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GXbOZnuQ-1660202182669)(C:\Users\17673\AppData\Roaming\Typora\typora-user-images\image-20220720170928978.png)]

现在我们只需要一个注解就可以替代之前要写一行配置的尴尬.

① 需要配置扫描路径

想要将对象成功的存储到 Spring 中,我们需要配置⼀下存储对象的扫描包路径,只有被配置的包下的所有类,添加了注解才能被正确的识别并保存到 Spring 中 ,在spring.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.test">
    </content:component-scan>
</beans>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HB9HePo8-1660202209103)(C:\Users\17673\AppData\Roaming\Typora\typora-user-images\image-20220720171440788.png)]

如果不是在配置的扫描包下的类对象,即使添加了注解,也不能被存储到Spring中的.

② 添加注解存储 Bean 对象

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

1.类注解:

@Controller – 控制器

使用@Controller 存储 bean 的代码如下:

 @Controller
public class UserController {
    public void sayHi(String name){
        System.out.println("Hi, " + name);
    }
}

使用之前的ApplicationContext来读取上面的 UserController 对象

public static void main(String[] args) {
        //1.得到上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        //2.得到Bean对象
        UserController userController = context.getBean("userController", UserController.class);
        //调用bean 方法
        userController.sayHi("张一");
    }

@Service – 服务

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

@Service
public class UserService {
    public void sayHi(String name){
        System.out.println("Hi, " + name);
    }
}

调取 bean 的代码

public static void main(String[] args) {
        //1.得到上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        //2. 得到Bean对象
        UserService userService = context.getBean("userService",UserService.class);
        //3.调用Bean
        userService.sayHi("张二");
    }

@Repoistory – 仓库

使用Repoistory 存储bean 的代码如下所示

@Repository
public class UserRepository {
    public void sayHi(String name){
        System.out.println("Hi, "  + name);
    }
}

读取 bean 的代码

public static void main(String[] args) {
        //1.得到上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        // 2.得到Bean
        UserRepository userRepository = context.getBean("userRepository",UserRepository.class);
        //3.调用Bean
        userRepository.sayHi("张三");

    }

@Configuration – 配置

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

@Configuration
public class UserConfiguration {
    public void sayHi(String name){
        System.out.println("Hi, " + name);
    }
}

读取 bean 的代码

public static void main(String[] args) {
        //1.得到上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        //2.得到bean
        UserConfiguration userConfiguration = context.getBean("userConfiguration",UserConfiguration.class);
        //3.调用Bean
        userConfiguration.sayHi("张四");
    }

@Component – 组件

使用 @Component 存储 bean 的代码如下

@Component
public class UserComponent {
    public void sayHi(String name){
        System.out.println("Hi, " + name);
    }

读取 bean

public static void main(String[] args) {
        //1.得到上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        UserComponent userComponent =  context.getBean("userComponent",UserComponent.class);
        userComponent.sayHi("张五");
    }

③ 为什么要这么多类注解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uzPH2g1J-1660202182671)(C:\Users\17673\AppData\Roaming\Typora\typora-user-images\image-20220720185247566.png)]

④ 类注解之间的关系

@Controller, @Service, @Repository, @Configuration 都是基于 @Component 实现的,所以@Component 可以认为是其它4个注解的父类

⑤方法注解**@Bean方法**

@Component
public class Users {
    @Bean(name = {"u1"})
    public User user1(){
        User user = new User();
        user.setId(1);
        user.setName("java");
        return user;
    }

取对象

public static void main(String[] args) {
        //1.得到 spring
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        //2.得到某个 bean
        User user = (User) context.getBean("u1");
        System.out.println(user);
    }

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FRAZieHi-1660202182671)(C:\Users\17673\AppData\Roaming\Typora\typora-user-images\image-20220720192636363.png)]

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

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

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

  1. 属性注入
  2. 构造方法注入
  3. Setter 注入

1. 属性注入

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

Service 类的实现代码如下

@Service
public class UserService {

    public User getUser(Integer id){
        User user = new User();
        user.setId(id);
        user.setName("Java-"+id);
        return user;
    }
}

Controller类的实现代码如下:

@Controller
public class UserController {
    //注入方法1: 属性注入
    @Autowired
    private UserService userService;
    public User getUser(Integer id){
        return userService.getUser(id);
    }
}

获取Controller 中的getUser方法:

public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
       UserController userController =  context.getBean(UserController.class);
        System.out.println(userController.getUser(1).toString());
    }

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c3Fo9k2u-1660202182672)(C:\Users\17673\AppData\Roaming\Typora\typora-user-images\image-20220720194823689.png)]

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);
    }
}

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 User getUser(Integer id){
        return userService.getUser(id);
    }

4.三种注入优缺点分析

  • 属性注⼊的优点是简洁,使⽤⽅便;缺点是只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空指针异常)
  • 构造方法注入是Spring 推荐的注入方式,它的缺点是如果有多个注⼊会显得⽐较臃肿,但出现这种情况你应该考虑⼀下当前类是否符合程序的单⼀职责的设计模式了,它的优点是通⽤性,在使⽤之
    前⼀定能把保证注⼊的类不为空
  • Setter ⽅式是 Spring 前期版本推荐的注⼊⽅式,但通⽤性不如构造⽅法,所有 Spring 现版本已经推荐使⽤构造⽅法注⼊的⽅式来进⾏类注⼊了

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

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

@Controller
public class UserController {
    //注入方法1: 属性注入
    @Resource
    private UserService userService;
    public User getUser(Integer id){
        return userService.getUser(id);
    }
}

@Autowired 和 @Resource 的区别

  • 出身不同:@Autowired 来⾃于 Spring,⽽ @Resource 来⾃于 JDK 的注解
  • 使⽤时设置的参数不同:相⽐于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如 name设置,根据名称获取 Bean

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("C++");
        return user;
    }
}

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

@Controller
public class UserController4 {
    @Resource
    private User user;
    public User getUser(){
        return user;
    }
}

以上程序的执⾏结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NC5NwgZQ-1660202182672)(C:\Users\17673\AppData\Roaming\Typora\typora-user-images\image-20220720201248959.png)]

报错的原因,非唯一的Bean对象

同一类型多个Bean 报错处理

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

  • 使⽤ @Resource(name=“user1”) 定义
  • 使⽤ @Qualifier 注解定义名称

使⽤ @Resource(name=“XXX”)

@Controller
public class UserController4 {
    @Resource(name = "user1")
    private User user;
    public User getUser(){
        return user;
    }
}

使用@Qualifier

@Controller
public class UserController5 {
    // 注⼊
    @Autowired
    @Qualifier(value = "user2")
    private User user;
    public User getUser() {
        return user;
    }
}
本文含有隐藏内容,请 开通VIP 后查看