Spring更简单的读取和存储对象
我们现在已经可以实现基本的Spring读取和存储对象的操作了,但在操作过程当中。我们发现并没有那么简单。在Spring当中想要更简单的存储和使用对象的核心是使用注解接下了就了解下,如何使用注解来存储和获取Bean
1. 存储Bean对象
之前存储Bean对象,需要添加一行bean才能注册,如下图所示:
而现在只需要一个注解,就可以代替一行的配置,但是我们先要来点准备工作
1.1 前置工作:配置扫描路径
注意:想要把Bean成功的存储到Spring当中,我们需要配置一下存储对象的扫描包路径,只有被配置的包下的所有类,添加了注解才能被正确识别并保存到Spring当中
在spring-config.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.example.beans"></content:component-scan> </beans>
圈起来的是扫描路径,表示所有要存放到Spring中的Bean的根目录
1.2 添加注解存储Bean对象
想要将对象存储到Spring当中,有两种注解类型可以实现:
- 类注解:
@Controller @Service @Repository @Component @Configuration
- 方法注解:
@Bean
接下来,分别来看:
1.2.1 @Controller(控制器存储)
@Controller public class UserController { public void sayHi() { System.out.println("你好Controller"); } }
这时我们按照之前的方法获取到Spring中的Bean
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); UserController userController = context.getBean("userController", UserController.class); userController.sayHi();
1.2.2 @Service(服务存储)
@Service public class UserService { public void sayHi() { System.out.println("你好Service"); } }
1.2.3 @Repository(仓库存储)
@Repository public class UserRepository { public void sayHi() { System.out.println("你好Repository"); } }
1.2.4 @Component(组件存储)
@Component public class UserComponent { public void sayHi() { System.out.println("你好Component"); } }
1.2.5 @Configuration
@Configuration public class UserConfiguration { public void sayHi() { System.out.println("你好Configuration"); } }
1.3 为什么要这么多类注解
既然功能都是一样的,为什么需要这么多呢?
这和为什么每个省/市都有自己的车牌号是一样的?比如陕西车牌号就是:陕XXXXXX,北京车牌号是:京XXXXXXXX。甚至一个省不同的县区车牌号都是不一样的。这样做的好处就是节约了号码,更重要的是可以直观的标识一辆车的归属地
那么为什么需要这么多类的注解也是相同的原因,就是让程序员看到类注解之后,就直接了解当前类的用途。
让代码的可读性提高,让程序员能够直观的判断当前类的用途
比如:
@Controller
表示业务逻辑层@Service
表示服务层@Repository
表示持久层@Configuration
表示配置层
程序的工程分层,调用流程如下:
1.3.1 类注解之间的关系
查看@Controller、@Service、@Repository、@Configuration
等注解可以发现:<img
这些类注解里面都有一个注解@Component
,说明它们本身就属于@Component
的“子类”
1.3.2 Bean命名规则
通过场面的例子我们可以看出,通常我们bean使用的都是标准大驼峰的命名,而读取的时候首字母小写就可以获取到bean了。
然后当我们首字母和第二个字母都大写的时候,就不能正常的读取到Bean了
这个时候我们就要查询Spring关于Bean存储时生成的命名规则了
源码如下:
public static String decapitalize(String name) { if (name == null || name.length() == 0) { return name; } 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.4 方法注解
类注解是添加到某个类上的,而方法注解是放到某个方法当中,如以下代码实现:
public class UserBean { @Bean public void sayHi() { System.out.println("你好bean"); } }
但是我们发现根本获取不到。这是为什么?
1.4.1 方法注解要配合类注解来使用
在Spring框架当中,方法注解@Bean要配合类注解才能将对象正常的存储到Spring容器当中,如下代码:
@Component public class UserBean { @Bean public User getUser() { User user = new User(); user.setId(1); user.setName("张三"); return user; } }
1.4.2 重命名Bean
可以通过设置name属性给Bean对象进行重命名操作
@Component public class UserBean { @Bean(name = "user") public User getUser() { User user = new User(); user.setId(1); user.setName("张三"); return user; } }
Bean命名规则:当没有设置name属性的时候,那么bean默认的名称就是方法名,当设置了name属性之后,只能通过重命名的那么属性对应的值来获取。也就是说,重命名之后再使用方法名就获取不到了
2. 获取Bean对象(对象装配)
获取bean对象也叫对象装配,是把对象取出来放到某个类当中,也时候也叫作对象注入
对象装配的实现有以下3中方法:
- 属性注入
- 构造方法注入
- Setter注入
2.1 属性注入
2.2 构造方法注入
如果当前类当中只存在一个构造方法,那么@Autowired注解可以省略
2.3 Setter注入
2.4 三种注入的优缺点
- 属性输入的优点是简介、使用方便;缺点是只能用于IOC容器,如果不是IOC容器不可用,并且只有在使用的时候才会出现NPE(空指针异常)
- 构造方法注入是Spring推荐的注入方式。它的缺点是如果有多个注入会显得比较臃肿,但是出现这种情况应该考虑一下当前类是否符合程序的单一职责的设计模式了,它的有点在于通用性,在使用之前,一定能保证注入的类不为空
- Setter方式是Spring前期版本推荐的注入方式,但是通用性不如构造方法,所有Spring版本已经推荐使用构造方法来注入了
2.5 @Resource:另一种注入关键字
@Autowired和@Resource的区别:
- 出身不同:@Autowired 来自于Spring,而@Resource来自于JDK的注解
- 使用时设置的参数不同:@Resource支持更多的参数设置,例如name设置,根据名称获取Bean
- @Autowired可用于Setter注入、构造函数注入、属性注入,而@Resource只能用于Setter和属性注入,不用用于构造函数注入
2.6 同一个类型多个@Bean报错
解决方案有以下两种:
- 使用@Resource(name=“user1”)定义
- 使用@Qualifier注解定义名称
@Controller public class UserController5 { // 注⼊ @Autowired @Qualifier(value = "user2") private User user; public User getUser() { return user; } }
3. 总结
- 将对象存储到Spring中:
- 使用类注解:@Controller、@Service、@Repository、@Configuration、@Component【它们之间的关系】
- 使用方法注解:@Bean【注意事项:必须配合类注解一起使用】
- Bean的命名规则:首字母和第二个字母都不是大写,首字母小写来获取Bean,如果首字母和第二个字母都是大写,那么直接使用Bean名来获取Bean
- 从Spring中获取对象
- 属性注入
- Setter注入
- 构造方法注入(推荐)
- 注入的关键字有
- @Autowired
- @Resource
- @Autowired 和 @Resource 区别:出身不同;使用是设置参数不同@Resource支持更多的参数设置
- 解决同一个类型多个Bean的报错
- 使用@Resource(name = “”)
- 使用@Qualifier(“”)