目录
存储Bean
上篇文章的存储Bean是在Spring的配置文件下通过bean标签来把Bean存储到Spring容器中,其中需要设置标签属性id 和 name,还是比较麻烦的,接下来介绍一种更为简单也最为常用的方法来存储Bean。
配置文件中设置扫描路径
首先还是要在配置文佳中设置一下。这里需要设置的是要存储的Bean对象的路径。
比如我想把test包下面的这几个类存储到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">
<!-- 设置的扫描路径 -->
<content:component-scan base-package="com.test"></content:component-scan>
</beans>
有关扫描路径需要注意的点:
1. 只有在扫描路径下的类,加了注解的才能被存储到Spring中
2. 扫描路径是可以提升效率的,不至于在整个项目中找要存储的类
使用注解存储Bean
上述工作完成后就可以通过注解存储Bean。注解分为两大类,一类是类注解,一类是方法注解。
五大类注解存储Bean
这五个注解分别是 @Controller @Component @Configuration @Repository @Service
使用演示:
package com.test;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
public void doController() {
System.out.println("doUserController");
}
}
import com.test.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
// 获取到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// 测试Controller
UserController userController = context.getBean("userController", UserController.class);
userController.doController();
}
}
上面获取到Bean时,第一个参数直接就是把类的第一个字母小写了(大驼峰变成小驼峰)
这只是其中的一个对Bean名字的处理方式,接下来来看另外一种。
package com.test;
import org.springframework.stereotype.Controller;
// 当类的第一、二的字母都是大写的情况
@Controller
public class UController {
public void doController() {
System.out.println("doUController");
}
}
为什么会有两个处理情况,通过查看源码可知。
其他四个注解也都是相同的命名规则,也是相同的用法,就不一一演示了。
小结:
1. 使用注解来存储的前提是配置文件中已经设置好了路径
2. 只有在配置文件路径下加了注解才能把Bean存储到Spring中,二者同时成立才可以
3. 取出Spring的bean时,有两种方法:
a. 如果类名的前两个字母并非都为大写字母,则在取的时候变成首字母小写
b. 如果前两个字母都是大写,在取的时候使用原类名即可
五大类注解之间的关系
可以看出,@Service @Repository @Controller @Configuration 这四个注解都是相当于 拓展了 @Component 这个注解,所以它们的使用方式基本都一致。
为什么要有五大类注解
当程序员看到五大类注解后,就会知道这个类具体是干什么的。
@Bean方法注解存储方法返回值
1. 在配置文件中把把方法所在的类的路径配置好
2. 在方法上加@Bean注解,同时在方法所在的类上面加上五大类注解
package com.test.component;
import com.test.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class UserBeans {
@Bean
public User getUserById() {
User user = new User();
user.setUserId(1);
user.setUserName("张三");
user.setUserAge(20);
return user;
}
}
import com.test.entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
// 获取到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// 测试Bean注解
User user = context.getBean("getUserById", User.class);
System.out.println(user.getUserName());
}
}
如果不加类注解:
上面获取到方法返回的Bean是通过方法名,这和之前五大注解的获取Bean又是另外一套规则。但是通过方法名获取通常是不使用的,我们可以在@Bean注解后重写命名,通过新名字来获取,同时使用原方法名就获取不到Bean了。
小结:
1. @Bean方法注解必须在五大类注解下使用(被五大类修饰的类)
2. 该注解如果没用重命名,那么直接使用方法名就可以获取到Bean
3. 如果重命名后,只能使用新的名字,方法名无法继续使用
4. 新名字可以有很多,使用数组保存
5. 该注解是把方法的返回值存入到Spring中,如果方法没有返回值,就不能使用该注解
注入Bean
把对象从Spring中取出来到某个类中使用。
属性注入
package com.test.service;
// 测试从Spring中拿user对象注入UserController类中
import com.test.entity.User;
import org.springframework.stereotype.Service;
@Service()
public class UserService {
// 实际上要连接数据库通过id查询到对象
public User getUser(Integer id) {
User user = new User();
user.setUserName("张三");
user.setUserId(123);
user.setUserAge(20);
return user;
}
}
package com.test.controller;
import com.test.entity.User;
import com.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
// 通过属性注入
@Autowired
private UserService userService;
public User getUserByAttribute(Integer id) {
return userService.getUser(id);
}
}
import com.test.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App2 {
public static void main(String[] args) {
// 获取到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// 获取到Bean对象
UserController userController = context.getBean("userController", UserController.class);
System.out.println(userController.getUserByAttribute(123).toString());
}
}
优点:
高效便捷:使用属性注入时,无需编写额外的构造方法或Setter方法,可以大大降低代码量并提高开发效率。
可读性强,很容易从代码层面看出有哪些Bean被注入了
缺点:
- 无法注入final修饰的修饰的对象。因为final修饰的对象只能被赋值一次,而在Spring容器中,属性注入是通过反射实现的,它需要通过反射来修改对象的属性值,但是final修饰的对象属性是不可变的,不能被修改,因此无法进行属性注入。
- 对象有可能会被修改。因为注入的Bean可以使用很多次。
- 只能在IoC容器下使用,其他的不行
- 不能保证对象完全初始化 原因有以下两点:
a:Bean依赖关系不完整,当某个Bean依赖的其他Bean还未完全初始化或者还未注 入时就会出现这种情况。
b:Bean的声明周期管理不当(下篇文章讲)
Setter方法注入
package com.test.controller;
import com.test.entity.User;
import com.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
private UserService userService;
// 通过Setter方法注入
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public User getUserBySetter(Integer id) {
return userService.getUser(id);
}
}
import com.test.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App2 {
public static void main(String[] args) {
// 获取到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// 获取到Bean对象
UserController userController = context.getBean("userController", UserController.class);
System.out.println(userController.getUserBySetter(123).toString());
}
}
优点:
- 灵活性高,相较于构造方法注入,它可以在任何时候注入
- 符合单一设计原则(每个方法只传一个对象)
缺点:
- 不能注入final修饰的对象。只用Java8及以下的不可以,原因同上。但是Java9及以后的可以,因为引入了Variable Handles的机制,可以通过反射来修改final字段的值。
- 对象可能会被修改
构造方法注入
package com.test.controller;
import com.test.entity.User;
import com.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
private UserService userService;
// 通过构造方法注入
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
public User getUserByConstructor (Integer id) {
return userService.getUser(id);
}
}
import com.test.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App2 {
public static void main(String[] args) {
// 获取到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// 获取到Bean对象
UserController userController = context.getBean("userController", UserController.class);
System.out.println(userController.getUserByConstructor(123).toString());
}
}
特点:
当只有一个构造方法的时候,@AutoWired这个注解可以省略
因为这是官方推荐使用的方法
优点:
- 可以注入一个被final修饰的对象。因为除了一开始就赋值,还可以在构造方法中对final修饰的属性赋值。
- 被注入的对象不可变。因为构造方法只能在最开始执行一次。
- 可以保证被注入的对象完全初始化
- 通用性更好,可以在IoC之外的地方使用。
@Resource注解
这是JDK提供的注入Bean的注解,和@AutoWired有以下的区别。
- @Resource是JDK提供的,@AutoWired是Spring提供的
- @Resource只能不能使用构造方法注入,@AutoWired都可以
- @Resource可以设置很多参数,而@AutoWired只能设置一个
有什么错误评论区指出。希望可以帮到你。