准备工作
从 Spring 2.5 开始就可以使用注解来配置依赖注入,只需要在相关类、方法、属性上声明注解即可。
需要注意的是,默认情况下,Spring 容器中注解是不生效的,因此在配置使用注解之前需要在 Spring 配置文件中启用它。
配置注解生效的步骤:
1. 在根标签 <beans> 中加上 context 命名空间,并为其设置 schemaLocation
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlsn:context="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
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
2. 在根标签 <beans> 内,加上<context:annotation-config />
<beans>
<!-- 启用注解配置 -->
<context:annotation-config />
</beans>
注解配置
@Required 注解
Required —— 必需的。
可以使用位置: 在所对应的属性的 set 方法上。
作用: 通过 Spring 形式对这个类实例化时,必须对这个属性进行 set,也就是说必须给这个属性赋值。
@Required
public void setName(String name) {
this.name = name;
}
如果将在某个属性的 set 方法上加了 @Required 注解,但是在实例其对象时,没有对该属性赋值,会抛出 Bean 实例化失败的异常:org.springframework.beans.factory.BeanInitializationException
@Autowired 注解
@Autowired 注解对应我们在 Spring XML 配置中 bean 标签的 autowire 属性。
PS:属性没有 d,注解有 d。
默认情况下,@Autowired 注入首先根据 byType 注入,如果 byType 查找到的 bean 是多个时,根据 byName 注入。
可以使用位置: set 方法上、放在属性上(此时可以省略 set 方法)、构造方法上
// 放在 set 方法上
@Autowired
public void setD1(Demo1 obj1) {
this.d1 = obj1;
}
// 放在属性上,此时可省略 set 方法
@Autowired
private Demo1 d1;
// 放在构造方法上
@Autowired
public Demo3(Demo1 d1){
this.d1 = d1;
}
1. 默认情况下,@Autowired 注解 是必须要进行自动装配的,也就是要求 Spring 容器中至少有一个 Demo1 类型的 bean,否则报错
@Autowired
public void setD1(Demo1 d1) {
this.d1 = d1;
}
2. 可以通过 @Autowired(required = false)
的方式设置为 Spring 容器中,没有对应类型的 bean,就不进行自动装入。
@Autowired(required = false)
public void setD1(Demo1 d1) {
this.d1 = d1;
}
3. 那如果 Spring 容器中,有多个对应类型的 bean 呢?@Autowired 注解按照 byType 方式查找,得到可以赋值的类型的 bean 数目大于 1 时,会按照 byName 方式进行装载,如果按照 byName 方式也找不到一个唯一的 bean,会抛出 bean 不唯一的异常。
小结:
- 使用 @Autowired注解,如果在 Spring 容器中找不到 bean,会抛出异常。
- 使用 @Autowired(required = false),如果在 Spring 容器中找不到 bean,不进行自动装载。
- 如果找到的合适类型的 bean 不止一个,进行 byName 方法进行查找,如果使用 byName 方式也找不到唯一的一个 bean,抛出不唯一异常。
- 第3种情况可以搭配 @Qualifier 注解解决。
@Autowired 注解放在 set 方法上,如果 set 方法的参数名和属性名不相同,如下面 Demo3 的属性名是 d1,设置这个属性的 set 方法的参数名是 obj1。按照 byType 在 Spring 容器中查找,找到了一个和属性名相同Demo1 类型的 bean —— obj1,找到了一个和参数名相同 Demo1 类型的bean —— name,此时 Autowired 按照 byName 查找时到底会按照属性名还是参数名查找?答:按照 set 方法的参数名查找。
public class Demo3 {
private Demo1 d1;
@Autowired(required = false)
public void setD1(Demo1 obj1) {
this.d1 = obj1;
}
}
<bean class="model.Demo1" id="obj1" p:name="111"></bean>
<bean class="model.Demo1" id="name" p:name="333"></bean>
<bean class="model.Demo3" id="obj"></bean>
public static void main(String[] args) {
String xmlPath = "spring/testAnnotation.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
Demo3 d1 = (Demo3) context.getBean("obj");
System.out.println(d1);
}
结果:
@Qualifier 注解
Qualifier —— 取得资格的人,合格的人。
在进行自动装载时,按照类型查找,如果找到了多个 bean,搭配 @Qualifier(“实现类的名字”),指定需要注入的 bean。
@Resource 注解
Resource 注解常用于和 Autowired 注解对比考察。
@Resource | @Autowired | |
提供厂商 | Jdk | Spring |
使用形式 | 先 byName,如果处理不了再 byType | 先 byType,如果处理不了再 byName |
不带参数时,表示从容器中找到和属性名相同的 bean 注入
带参数时,表示从容器中找到和参数名相同的 bean 注入给属性
// 从容器中找名为 d1 的 bean 注入给 d1
@Resource
private Demo1 d1;
// 从容器中找名为 obj1 的 bean 注入给 d2
@Resource("obj1")
private Demo1 d2;
@Controller 注解
Controller —— 控制器。
@Controller 注解是放在控制层的实现类上,此时,Spring 容器在加载的时候,如果知道 @Controller 注解这个注解在哪里,就会将 @Controller 注解修饰的类的实例放到 Spring 容器中。
这个过程就 IOC 的过程。
后面的 @Service 注解、@Repository 注解、@Component 注解都是差不多的
@Service 注解
@Service 注解是放在业务层实现类上
@Repository 注解
@Repository 注解是放在数据层实现类上
@Component 注解
Component —— 组件。
@Component 注解将其修饰的类的实例交由 Spring 容器处理。
@Component 注解一般应用于除了控制层、业务层、数据层的实现类之外的类上,一般是在 Spring-Boot 中用的比较多。
使用
@Controller 注解、@Service 注解、@Repository 注解在使用的时候有两种常用形式,一种不带参数,一种带参数。
@Controller
public class Test1Controller{}
@Controller("test")
public class Test2Controller{}
不带有参数的形式,会将其所修饰的类实例化对象交由 Spring 容器管理,其中实例的名字为类名的首字母小写,如上面代码中的 Test1Controller 类的实例名就是 test1Controller
带有参数的形式,会将其所修饰的类实例化对象交由 Spring 容器管理,其中实例的名字为参数名,如上面代码中的 Test2Controller 类的实例名就是 test
最后一个知识点:前面使用@Controller 注解、@Service 注解、@Repository 注解、@Component 注解修饰的类,需要进行扫描才会放入到 Spring 容器中。
这个扫描操作需要在 Spring 配置文件中进行
<context:component-scan base-package="" />
这个 XML 标签的作用就是从 base-package 中写的包开始,扫描那些被组件注解修饰的类,扫描到了之后,将这些类解析,创建实例之后,放入到 Spring 容器中。
回顾在 Spring 配置文件中需要写的内容
1. 命名空间中创建 context 命名空间,并配置 xsi:schemaLocation
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlsn:context="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
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
2. 启动注解
<context:annotation-config></context:annotation-config>
3. 从某个包开始,扫描组件
<context:component-scan base-package="包名">