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

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

1. Spring 更简单的存储对象

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

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

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:content="http://www.springframework.org/schema/context"
  5. 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">
  6. <!-- 配置 Spring 扫描的根路径(此根路径下的所有 Spring 存对象的注解才能生效) -->
  7. <content:component-scan base-package="com.wwzz"></content:component-scan>
  8. </beans>

注意这两个地方要匹配.

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

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

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

1.3 类注解

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

  1. package com.wwzz.controller;
  2. import org.springframework.stereotype.Controller;
  3. @Controller
  4. public class UserController {
  5. /**
  6. * 这个方法只是用来测试的
  7. * @param name
  8. */
  9. public void SayHello(String name){
  10. System.out.println("Hello! " + name);
  11. }
  12. }

② @Service 服务存储

  1. package com.wwzz.service;
  2. import org.springframework.stereotype.Service;
  3. @Service
  4. public class UserService {
  5. public void SayHello(String name){
  6. System.out.println("Hello! " + name);
  7. }
  8. }

③ @Repository (仓库存储)

  1. package com.wwzz.dao;
  2. import org.springframework.stereotype.Repository;
  3. @Repository
  4. public class UserRepository {
  5. public void SayHello(String name){
  6. System.out.println("Hello! " + name);
  7. }
  8. }

④ @Component (组件存储)

  1. package com.wwzz.util;
  2. import org.springframework.stereotype.Component;
  3. @Component
  4. public class UserComponent {
  5. public void SayHello(String name){
  6. System.out.println("Hello! " + name);
  7. }
  8. }

⑤ @Configuration (配置存储)

  1. package com.wwzz.config;
  2. import org.springframework.context.annotation.Configuration;
  3. @Configuration
  4. public class UserConfiguration {
  5. public void SayHello(String name){
  6. System.out.println("Hello! " + name);
  7. }
  8. }

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

  1. package com.wwzz;
  2. import com.wwzz.config.UserConfiguration;
  3. import com.wwzz.controller.UserController;
  4. import com.wwzz.dao.UserRepository;
  5. import com.wwzz.service.UserService;
  6. import com.wwzz.util.UserComponent;
  7. import org.springframework.context.ApplicationContext;
  8. import org.springframework.context.support.ClassPathXmlApplicationContext;
  9. public class App {
  10. public static void main(String[] args) {
  11. ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
  12. UserController userController = context.getBean("userController", UserController.class);
  13. userController.SayHello("Controller");
  14. UserService userService = context.getBean("userService",UserService.class);
  15. userService.SayHello("UserService");
  16. UserRepository userRepository = context.getBean("userRepository",UserRepository.class);
  17. userRepository.SayHello("UserRepository");
  18. UserComponent userComponent = context.getBean("userComponent",UserComponent.class);
  19. userComponent.SayHello("UserComponent");
  20. UserConfiguration userConfiguration = context.getBean("userConfiguration", UserConfiguration.class);
  21. userConfiguration.SayHello("UserConfiguration");
  22. }
  23. }

注意事项

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

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

观察源码

所以正确的是使用 UComponent

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

1.4 类注解直接的关系

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

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

1.5 方法注解

① @Bean

首先创建一个类User

  1. public class User {
  2. public int id;
  3. public String name;
  4. public int age;
  5. // ... 一堆 getter和setter
  6. }

创建一个UserBean

  1. package com.wwzz.util;
  2. import com.wwzz.model.User;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.stereotype.Component;
  5. @Component
  6. public class UserBean {
  7. @Bean
  8. public User user() {
  9. // 伪代码 获取数据库中的内容....
  10. User user = new User();
  11. user.setId(1);
  12. user.setName("张三");
  13. user.setAge(18);
  14. return user;
  15. }
  16. }

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

方法注解 重命名 Bean

  1. import com.wwzz.model.User;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.stereotype.Component;
  4. @Component
  5. public class UserBean {
  6. @Bean(name = {"u1","u2"})
  7. public User user() {
  8. // 伪代码 获取数据库中的内容....
  9. User user = new User();
  10. user.setId(1);
  11. user.setName("张三");
  12. user.setAge(18);
  13. return user;
  14. }
  15. }

测试这个重命名.

注意事项

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

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

2. Spring 更简单的获取对象

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

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

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

  1. package com.wwzz.service;
  2. import com.wwzz.model.User;
  3. import org.springframework.stereotype.Service;
  4. @Service
  5. public class UserService {
  6. /**
  7. * 根据用户id获取用户对象
  8. * @param id
  9. * @return
  10. */
  11. public User findUserById(int id){
  12. // 伪代码 返回用户对象
  13. User user = new User();
  14. if (id == 1){
  15. user.setId(1);
  16. user.setName("张三");
  17. user.setAge(18);
  18. }else {
  19. user.setId(2);
  20. user.setName("李四");
  21. user.setAge(20);
  22. }
  23. return user;
  24. }
  25. }

2.1 属性注入

代码示例

  1. package com.wwzz.controller;
  2. import com.wwzz.model.User;
  3. import com.wwzz.service.UserService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Controller;
  6. @Controller
  7. public class UserController {
  8. // 1. 属性注入 从Spring 中获取一个对象, 并注入到当前类
  9. @Autowired
  10. private UserService userService;
  11. public User findUserById(Integer id) {
  12. if (id == null){
  13. return new User();
  14. }
  15. return userService.findUserById(id);
  16. }
  17. }

运行测试:

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

2.2 构造方法注入

代码示例

  1. package com.wwzz.controller;
  2. import com.wwzz.model.User;
  3. import com.wwzz.service.UserService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Controller;
  6. @Controller
  7. public class UserController2 {
  8. private UserService userService;
  9. // 方法二: 构造方法注入是在类的构造方法种实现注入
  10. @Autowired
  11. public UserController2(UserService userService) {
  12. this.userService = userService;
  13. }
  14. public User findUserById(Integer id){
  15. if(id == null){
  16. return null;
  17. }
  18. return userService.findUserById(id);
  19. }
  20. }

运行测试:

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

注意事项

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

2.3 Setter 注入

代码示例

  1. package com.wwzz.controller;
  2. import com.wwzz.model.User;
  3. import com.wwzz.service.UserService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Controller;
  6. @Controller
  7. public class UserController1 {
  8. // 1. 将 UserService 注入到当前类(使用Setter)
  9. private UserService userService;
  10. @Autowired // 必须要添加
  11. public void setUserService(UserService userService) {
  12. this.userService = userService;
  13. }
  14. // 2. 新建一个方法, 在方法里面调用 UserService 的查询方法. 返回用户对象
  15. public User findUserById(Integer id){
  16. if(id == null){
  17. return null;
  18. }
  19. return userService.findUserById(id);
  20. }
  21. }

运行测试:

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

2.4 三种注入方式的优缺点

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

2.5 @Resource 另一种注入方式

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

2.5.1 属性注入

  1. package com.wwzz.controller;
  2. import com.wwzz.model.User;
  3. import com.wwzz.service.UserService;
  4. import org.springframework.stereotype.Controller;
  5. import javax.annotation.Resource;
  6. @Controller
  7. public class UserController {
  8. @Resource
  9. private UserService userService;
  10. public User findUserById(Integer id) {
  11. if (id == null){
  12. return new User();
  13. }
  14. return userService.findUserById(id);
  15. }
  16. }

2.5.2 Setter 注入

  1. package com.wwzz.controller;
  2. import com.wwzz.model.User;
  3. import com.wwzz.service.UserService;
  4. import org.springframework.stereotype.Controller;
  5. import javax.annotation.Resource;
  6. @Controller
  7. public class UserController1 {
  8. // 1. 将 UserService 注入到当前类(使用Setter)
  9. private UserService userService;
  10. @Resource
  11. public void setUserService(UserService userService) {
  12. this.userService = userService;
  13. }
  14. // 2. 新建一个方法, 在方法里面调用 UserService 的查询方法. 返回用户对象
  15. public User findUserById(Integer id){
  16. if(id == null){
  17. return null;
  18. }
  19. return userService.findUserById(id);
  20. }
  21. }

2.6 @Autowired 和 @Resource的区别

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

2.7 同一类型多个@Bean报错

有如下一段代码

  1. package com.wwzz.util;
  2. import com.wwzz.model.User;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.stereotype.Component;
  5. @Component
  6. public class UserBean {
  7. @Bean
  8. public User user1() {
  9. // 伪代码 获取数据库中的内容....
  10. User user = new User();
  11. user.setId(1);
  12. user.setName("张三");
  13. user.setAge(18);
  14. return user;
  15. }
  16. @Bean
  17. public User user2() {
  18. User user = new User();
  19. user.setId(2);
  20. user.setName("李四");
  21. user.setAge(20);
  22. return user;
  23. }
  24. }

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

  1. package com.wwzz.controller;
  2. import com.wwzz.model.User;
  3. import org.springframework.stereotype.Controller;
  4. import javax.annotation.Resource;
  5. @Controller
  6. public class UserController5 {
  7. @Resource
  8. private User user;
  9. public User getUser() {
  10. return user;
  11. }
  12. }
  1. public static void main(String[] args) {
  2. ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
  3. UserController5 userController5 = context.getBean("userController5",UserController5.class);
  4. User user = userController5.getUser();
  5. System.out.println(user);
  6. }

运行结果:

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

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

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

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

相关文章

最新文章

更多