在没有使用注解获取对象之前,我们需要在配置文件中通过添加bean来将对象存储到Spring容器中,这对于我们来说是比较麻烦的。如果只有一两个对象那当然好说,但是一个项目的开发其对象数量肯定是很多的,那么此时我们使用注解就非常方便了。
#前置工作
注意:想要将对象成功的存储到 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 htt
p://www.springframework.org/schema/beans/spring-beans.xsd http://www.spring
framework.org/schema/context https://www.springframework.org/schema/contex
t/spring-context.xsd">
<content:component-scan base-package="com.example.demo"></content:compon
ent-scan>
</beans>
其中,base-packge是我们需要扫描的包路径,如果我们添加注解的类不在该路径下那么也是不能成功的存入容器中的。
#存对象的注解类型
在Spring中共有@Controller / @Service / @Repository / @Configuration/@Component这5个存取对象的注解,他们所能实现的功能相同,选用不同类型的注解不过是为了规范,让我们在开发中能够了解使用该注解的类是为哪个层次所服务的。⽐如陕⻄的⻋牌号就是:陕X:XXXXXX,北京的⻋ 牌号:京X:XXXXXX,⼀样。甚⾄⼀个省不同的县区也是不同的,⽐如⻄安就是,陕A:XXXXX,咸 阳:陕B:XXXXXX,宝鸡,陕C:XXXXXX,⼀样。这样做的好处除了可以节约号码之外,更重要的作 ⽤是可以直观的标识⼀辆⻋的归属地。这也是为什么需要怎么多的类注解的原因,就是让程序员看到类注解之后,就能直接了解当前类 的⽤途,⽐如: @Controller:表示的是业务逻辑层; @Servie:服务层; @Repository:持久层; @Configuration:配置层。
他们之间的逻辑关系如下:
另外其实这些注解⾥⾯都有⼀个注解 @Component,说明它们本身就是属于 @Component 的“⼦类”。
#注解的使用
由于这些注解的使用方法都是一样的所以我们在这里就只演示一种注解的使用。
@Controller
public class User {
private String name;
private int id;
private int score;
}
我们在这里给一个类添加Controller,之后就可以通过getBean来获取该对象。
public class App {
public static void main(String[] args) {
//1.得到spring上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("spring_config.xml");
//2.从spring中获取对象
//User user = (User)context.getBean("user");
User user = context.getBean("user",User.class);
}
}
这样我们就获取到了一个Bean对象。
不过在这里我们要注意一个地方,那就是在获取Bean的方法中我们使用的Bean的命名是有一定的规则的。
总的来说就是首字母要小写,比如类为User,那么就为user,为UserName就为userName,但是也有一个例外,那就是如果为UName,那么就还是为UName这是Spring所规定的Bean的命名的规则,我们遵循就好。
#方法注解Bean注解
在上面我们学习了类的注解,接下来我们就来了解一下方法的注解。
顾名思义,类注解是添加到类上的那么方法注解就是添加到方法上的。
@Controller
public class User {
private int id;
private String name;
public int getId() {
return id;
}
@Bean
public User getUser(){
return new User();
}
}
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring_config.xml");
User user = context.getBean("getUser",User.class);
context.close();
那么我们就可以通过方法的方法名来获取到对象,不过需要注意的是Bean注解是一定要搭配我们上面提到的类注解来使用的。这是为了提高系统查找的效率,因为我们在上面有提到添加了类注解的类是要指定他的查找路径的,这样就可以避免盲目的查找,提高效率。
Bean的命名
我们在默认不修改Bean的名称时它默认就是方法名,但是我们是可以改变它的名称的。
@Component
public class TestUser {
@Bean(name = {"user1,user2"})
public User getUser(){
return new User();
}
}
如上,我们就将名称修改为了user1或是user2,他是可以修改为一个或多个名称的。
#对象的注入:Autowired和Resource
除了通过getBean方法来获取对象,我们还可以通过对象注入的方式来获取对象。
在添加了类注解的类或是添加了方法注解的方法我们都可以通过注入的方式来获取
#.类注解
Autowired
展示类
@Controller
public class UserController{
public void Hi(){
new User();
System.out.println("Hello World");
}
}
1.属性注入
@Component
public class TestUser {
@Autowired
UserController userController;
public UserController getUserController(UserController userController){
this.userController = userController;
}
}
2.setter注入
@Component
public class TestUser {
UserController userController;
@Autowired
public void setUserController(UserController userController){
this.userController = userController;
}
}
3.构造方法注入
@Component
public class TestUser {
UserController userController;
@Autowired
public TestUser(UserController userController){
this.userController = userController;
}
}
获取对象
@Component
public class TestUser {
@Autowired
UserController userController;
public void test1(){
userController.Hi();
}
}
我们第一个类中添加类注解之后再第二个类中通过Autowired来获取到该对象。
我们在上面介绍了三种注入的方法,他们虽然都能获取到Bean对象但是他们也有各自的特点。
属性注⼊的优点是简洁,使⽤⽅便;缺点是只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只 有在使⽤的时候才会出现 NPE(空指针异常)。
构造⽅法注⼊是 Spring 推荐的注⼊⽅式,它的缺点是如果有多个注⼊会显得⽐较臃肿,但出现这 种情况你应该考虑⼀下当前类是否符合程序的单⼀职责的设计模式了,它的优点是通⽤性,在使⽤ 之前⼀定能把保证注⼊的类不为空。
Setter ⽅式是 Spring 前期版本推荐的注⼊⽅式,但通⽤性不如构造⽅法,所有 Spring 现版本已 经推荐使⽤构造⽅法注⼊的⽅式来进⾏类注⼊了。
#方法注解
@Component
public class TestUser {
@Bean
public User getUser(){
return new User();
}
}
@Controller
public class UserController{
@Autowired
@Qualifier(value = "getUser")
public User user;
}
同样的我们在第一个类中添加类标签和方法标签,这样我们就可以通过注入在另一处获取到该方法的返回值,不过在这里我们还需要另一个注解@Qualifier来对Bean进行筛选,因为如果存在多个Bean注解如果不用命名区分我们也就无法判断调用的是哪个Bean。
Resource
该标签的用法和Autowired基本一致,不过它拥有更多的方法,比如我们在上述中获取Bean对象需要额外的Qualifier标签而Resource就支持name方法就不需要额外的标签。
Autowired和Resource的不同
出身不同:@Autowired 来⾃于 Spring,⽽ @Resource 来⾃于 JDK 的注解;
使⽤时设置的参数不同:相⽐于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如 name 设置,根据名称获取 Bean。
@Autowired 可⽤于 Setter 注⼊、构造函数注⼊和属性注⼊,⽽ @Resource 只能⽤于 Setter 注 ⼊和属性注⼊,不能⽤于构造函数注⼊。