Java EE --- Spring 更简单的读取和存储对象

x33g5p2x  于2022-05-31 转载在 Java  
字(9.5k)|赞(0)|评价(0)|浏览(317)

1. Spring 更简单的存储对象

在Spring 中 想要更简单的读取和存储对象的核心就是使用注解.

1.1 配置 spring.xml 设置 spring 存入对象的根路径

<?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">

    <!-- 配置 Spring 扫描的根路径(此根路径下的所有 Spring 存对象的注解才能生效) -->
    <content:component-scan base-package="com.wwzz"></content:component-scan>

</beans>

注意这两个地方要匹配.

1.2 使用注解将 Bean 对象存储到 spring 中

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

  1. 类注解 :@Controller``@Service``@Repository``@Component``@Configuration
  2. 方法注解 :@Bean

1.3 类注解

① @Controller 控制器(对象的存储)

package com.wwzz.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
    /**
     * 这个方法只是用来测试的
     * @param name
     */
    public void SayHello(String name){
        System.out.println("Hello! " + name);
    }
}

② @Service 服务存储

package com.wwzz.service;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void SayHello(String name){
        System.out.println("Hello! " + name);
    }
}

③ @Repository (仓库存储)

package com.wwzz.dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {
    public void SayHello(String name){
        System.out.println("Hello! " + name);
    }
}

④ @Component (组件存储)

package com.wwzz.util;

import org.springframework.stereotype.Component;

@Component
public class UserComponent {
    public void SayHello(String name){
        System.out.println("Hello! " + name);
    }
}

⑤ @Configuration (配置存储)

package com.wwzz.config;

import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfiguration {
    public void SayHello(String name){
        System.out.println("Hello! " + name);
    }
}

测试这五个注解读取bean的代码

package com.wwzz;

import com.wwzz.config.UserConfiguration;
import com.wwzz.controller.UserController;
import com.wwzz.dao.UserRepository;
import com.wwzz.service.UserService;
import com.wwzz.util.UserComponent;
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.xml");
        UserController userController = context.getBean("userController", UserController.class);
        userController.SayHello("Controller");
        UserService userService = context.getBean("userService",UserService.class);
        userService.SayHello("UserService");
        UserRepository userRepository = context.getBean("userRepository",UserRepository.class);
        userRepository.SayHello("UserRepository");
        UserComponent userComponent = context.getBean("userComponent",UserComponent.class);
        userComponent.SayHello("UserComponent");
        UserConfiguration userConfiguration = context.getBean("userConfiguration", UserConfiguration.class);
        userConfiguration.SayHello("UserConfiguration");
    }
}

注意事项

  1. 读取存入对象的id 默认情况首字母要小写

  2. 当第一个字母和第二个字母都是大写的时候, 就不能正常读了

观察源码

所以正确的是使用 UComponent

  1. 对于存储目录. 必须要是之前约定好的, xml下里面的包目录下.

1.4 类注解直接的关系

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

这几个注解都有一个注解 @Component. 说明他们都是@Component的子类

1.5 方法注解

① @Bean

首先创建一个类User

public class User {
    public int id;
    public String name;
    public int age;
	// ... 一堆 getter和setter
}

创建一个UserBean

package com.wwzz.util;

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

@Component
public class UserBean {
    @Bean
    public User user() {
        // 伪代码 获取数据库中的内容....
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setAge(18);
        return user;
    }
}

测试这个注解读取到bean的代码

方法注解 重命名 Bean

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

@Component
public class UserBean {
    @Bean(name = {"u1","u2"})
    public User user() {
        // 伪代码 获取数据库中的内容....
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setAge(18);
        return user;
    }
}

测试这个重命名.

注意事项

  1. Spring 默认是类扫描, 要想使用 方法注解 @Bean 就需要配合类注解(@Component)一起使用, 才能将方法返回对象顺利存储到 Spring 中

  1. 重命名之后, 方法名就无法使用了

2. Spring 更简单的获取对象

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

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

下面例子是将 Service 类 注入到 Controller 类种
Service类中的代码

package com.wwzz.service;
import com.wwzz.model.User;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    /**
     * 根据用户id获取用户对象
     * @param id
     * @return
     */
    public User findUserById(int id){
        // 伪代码 返回用户对象
        User user = new User();
        if (id == 1){
            user.setId(1);
            user.setName("张三");
            user.setAge(18);
        }else {
            user.setId(2);
            user.setName("李四");
            user.setAge(20);
        }
        return user;
    }
}

2.1 属性注入

代码示例

package com.wwzz.controller;

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

@Controller
public class UserController {
    // 1. 属性注入 从Spring 中获取一个对象, 并注入到当前类
    @Autowired
    private UserService userService;

    public User findUserById(Integer id) {
        if (id == null){
            return new User();
        }
        return userService.findUserById(id);
    }
}

运行测试:

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

2.2 构造方法注入

代码示例

package com.wwzz.controller;

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

@Controller
public class UserController2 {
    private UserService userService;

    // 方法二: 构造方法注入是在类的构造方法种实现注入
    @Autowired
    public UserController2(UserService userService) {
        this.userService = userService;
    }
    public User findUserById(Integer id){
        if(id == null){
            return  null;
        }
        return userService.findUserById(id);
    }
}

运行测试:

public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        UserController2 userController2 = context.getBean("userController2",UserController2.class);
        User user = userController2.findUserById(1);
        System.out.println(user);
    }

注意事项

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

2.3 Setter 注入

代码示例

package com.wwzz.controller;

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

@Controller
public class UserController1 {
    // 1. 将 UserService 注入到当前类(使用Setter)
    private UserService userService;

    @Autowired // 必须要添加
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    // 2. 新建一个方法, 在方法里面调用 UserService 的查询方法. 返回用户对象
    public User findUserById(Integer id){
        if(id == null){
            return null;
        }
        return userService.findUserById(id);
    }
}

运行测试:

public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        UserController1 userController1 = context.getBean("userController1",UserController1.class);
        User user = userController1.findUserById(1);
        System.out.println(user);
    }

2.4 三种注入方式的优缺点

属性注入 :
优点: 简洁, 使用方便
缺点: 只能用于 IoC 容器, 如果是非 IoC 容器不可用, 并且只有在使用的时候才会出现 NPE (空指针异常)
 
构造方法注入 : Spring官方推荐的注入方式
优点: 通用性, 在使用之前一定能保证注入的类不为空
缺点: 如果有多个注入会显得比较臃肿
 
Setter 注入 : 通用性不如构造方法

2.5 @Resource 另一种注入方式

在进行注入的时候, 除了可以使用 @Autowired 关键字之外, 我们还可以使用 @Resource 进行注入.但是 @Resource 无法进行构造方法注入

2.5.1 属性注入

package com.wwzz.controller;

import com.wwzz.model.User;
import com.wwzz.service.UserService;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller
public class UserController {
    @Resource
    private UserService userService;

    public User findUserById(Integer id) {
        if (id == null){
            return new User();
        }
        return userService.findUserById(id);
    }
}

2.5.2 Setter 注入

package com.wwzz.controller;

import com.wwzz.model.User;
import com.wwzz.service.UserService;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller
public class UserController1 {
    // 1. 将 UserService 注入到当前类(使用Setter)
    private UserService userService;

    @Resource
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    // 2. 新建一个方法, 在方法里面调用 UserService 的查询方法. 返回用户对象
    public User findUserById(Integer id){
        if(id == null){
            return null;
        }
        return userService.findUserById(id);
    }
}

2.6 @Autowired 和 @Resource的区别

  1. 出生不同: @Autowired 来自 Spring 框架, @Resource 来自 JDK
  2. 作用范围不同: @Autowired 可以进行属性注入, 构造方法注入, Setter 注入. @Resource 可以进行 属性注入, Setter注入, 不能使用构造方法注入.
  3. 功能不同: 相比于 @Autowired, @Resource 支持更多的参数设置, 例如 name设置, 根据名称获取 Bean

2.7 同一类型多个@Bean报错

有如下一段代码

package com.wwzz.util;

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

@Component
public class UserBean {
    @Bean
    public User user1() {
        // 伪代码 获取数据库中的内容....
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setAge(18);
        return user;
    }
    @Bean
    public User user2() {
        User user = new User();
        user.setId(2);
        user.setName("李四");
        user.setAge(20);
        return user;
    }
}

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

package com.wwzz.controller;

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

import javax.annotation.Resource;

@Controller
public class UserController5 {
    @Resource
    private User user;

    public User getUser() {
        return user;
    }
}
public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        UserController5 userController5 = context.getBean("userController5",UserController5.class);
        User user = userController5.getUser();
        System.out.println(user);
    }

运行结果:

原因:
获取Bean对象的方法, 比如他们首先从名称获取, 如果获取不到, 就会从类型获取.
上面的代码, 从名称获取不到, 类型又有多个,就会注入失败.

解决办法1: 使用 @Resource(name=‘别名’)

解决办法2: 使用 @Qualifier 注解定义名称

这里配合@Autowired 和 @Resource 都可以

相关文章

微信公众号

最新文章

更多