四、注解配置IOC、DI
1、注解 @Component
我们这里有个类 Person
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package com.ys.annotation; public class Person { private int pid; private String pname; private String psex; public int getPid() { return pid; } public void setPid( int pid) { this .pid = pid; } public String getPname() { return pname; } public void setPname(String pname) { this .pname = pname; } public String getPsex() { return psex; } public void setPsex(String psex) { this .psex = psex; } } |
如果我们不使用注解,通过前面讲解的,要想让 Spring 容器帮我们产生 Person 对象,我们要进行如下配置:
applicationContext.xml 配置:
1
|
<bean id= "person" class = "com.ys.annotation.Person" ></bean> |
如果使用注解呢?
第一步:在 applicationContext.xml 中引入命名空间
这里我们简单讲解一下这里引入的命名空间,简单来说就是用来约束xml文件格式的。第一个 xmlns:context ,这表示标签格式应该是 <context:标签名>
第二步:在 applicationContext.xml 文件中引入注解扫描器
1
2
|
<!-- 组件扫描,扫描含有注解的类 --> <context:component-scan base- package = "com.ys.annotation" ></context:component-scan> |
base-package:表示含有注解类的包名
如果扫描多个包,则上面的代码书写多行,改变 base-package 里面的内容即可!
第三步:在 Person 类中添加注解@Component
第四步:测试
1
2
3
4
5
6
7
8
9
10
|
@Test public void testAnnotation(){ //1、启动 spring 容器 //2、从 spring 容器中取出数据 //3、通过对象调用方法 ApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml" ); Person person = (Person) context.getBean( "person" ); System.out.println(person.getPname()); } |
如果看完上面的注解配置,你一脸懵逼,那没关系,我们下面来详细讲解。
@Component
如果一个类上加了@Component注解,就会进行如下的法则
如果其value属性的值为""
@Component
public class Person {}
等价于
<bean id="person" class="..Person">
如果其value属性的值不为""
@Component("p")
public class Person {}
等价于
<bean id="p" class="..Person">
那么这就很好理解测试程序中,我们直接 context.getBean("person") 这样写。
2、@Repository @Service @Controller
此外:下面三个注解是 @Component 注解的衍生注解,功能一样
1
2
3
|
@Repository :dao层 @Service :service层 @Controller :web层 |
3、注解 @Resource
@Resource 注解,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Resource 的使用来消除 set ,get方法。
首先创建一个 学生类 Student.java
然后在 Person 类中添加一个属性 Student
那么我们如何获取 Person 对象,并调用 showStudent()方法呢?这个问题简化就是如何给属性 Student 实例化,也就是依赖注入
不使用注解:
1
2
3
4
|
<property name= "students" > <ref bean= "student" /> </property> <bean id= "student" class = "com.ys.annotation_di.Student" ></bean> |
使用注解:
@Resource注解以后,判断该注解name的属性是否为""(name没有写)
①、如果没有写name属性,则会让属性的名称的值和spring配置文件bean中ID的值做匹配(如果没有进行配置,也和注解@Component进行匹配),如果匹配成功则赋值,如果匹配不成功,则会按照spring配置文件class类型进行匹配,如果匹配不成功,则报错
②、如果有name属性,则会按照name属性的值和spring的bean中ID进行匹配,匹配成功,则赋值,不成功则报错
4、注解 @Autowired
功能和注解 @Resource 一样,可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。只不过注解@Resource 是按照名称来进行装配,而@Autowired 则是按照类型来进行装配。
第一步:创建接口 PersonDao
1
2
3
4
5
6
7
|
package com.ys.autowired; public interface PersonDao { public void savePerson(); } |
第二步:创建一个接口实现类 PersonDaoImplOne
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package com.ys.autowired; import org.springframework.stereotype.Component; @Component ( "personDaoImplOne" ) public class PersonDaoImplOne implements PersonDao{ @Override public void savePerson() { System.out.println( "save Person One" ); } } |
第三步:创建PersonService
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package com.ys.autowired; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service ( "personService" ) public class PersonService{ @Autowired private PersonDao personDao; public void savePerson() { this .personDao.savePerson(); } } |
注意:这里我们在 private PesronDao personDao 上面添加了注解 @Autowired,它首先会根据类型去匹配,PersonDao 是一个接口,它的实现类是 PesronDaoImpOne,那么这里的意思就是:
PersonDao personDao = new PersonDaoImpOne();
那么问题来了,如果 PersonDao 的实现类有多个呢?我们创建第一个实现类 PersonDaoImpTwo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package com.ys.autowired; import org.springframework.stereotype.Component; @Component ( "personDaoImplTwo" ) public class PersonDaoImplTwo implements PersonDao{ @Override public void savePerson() { System.out.println( "save Person Two" ); } } |
如果还是向上面那样写,那么测试就会报错。怎么解决呢?
第一种方法:更改名称
第二种方法:@Autowired 和 @Qualifier("名称") 配合使用
在使用@Autowired时,首先在容器中查询对应类型的bean
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
如果查询的结果不止一个,那么@Autowired会根据名称来查找。
如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false