上一章我们讲了无注解的自动装配:
https://blog.csdn.net/qq_34598667/article/details/83317377
这一章我们讲一下基于注解的装配,组件扫描
基于注解的组件扫描
案例准备:
之前案例com.oak.entity中的Person类
public class Person {
private String name;
private Integer age;
//构造方法等方法略
...
}
在包com.oak.dao中新建一个PersonDao接口如下:
public interface PersonDao {
void msg();
}
在同包下新建一个PersonDaoImpl实现PersonDao:
public class PersonDaoImpl implements PersonDao{
private Person person=new Person();
@Override
public void msg() {
System.out.println(person);
}
}
在包com.oak.service中新建PersonService类,调用PersonDao:
public class PersonService {
private PersonDao personDao=new PersonDaoImpl();
public void msg(){
personDao.msg();
}
}
以上述代码为例解析注解
什么是组件扫描?
我们之前的案例中发现,在创建bean时需要在xml中配置大量的< bean >定义,书写过于复杂。我们可以指定一个包路径,让spring自动扫描该包(及子包)下所有的组件类,当发现类定义了前有特定的spring注解时,就在spring容器中创建其对应的bean。等价于在xml中配置。
指定组件扫描路径
在xml中使用<context:component-scan base-package=“指定包路径”>指定扫描路径
注意:有些同学在加入这一句话之后会有报错,不要忘了声明xml命名空间,在beans中添加
xmlns:context="http://www.springframework.org/schema/context"
在schemaLocation中添加
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
添加之后的代码为:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns: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-4.2.xsd">
<!--指定注解扫描包路径-->
<context:component-scan base-package="com.oak"/>
</beans>
如果实例化容器时出现嵌套异常,则需要导入aop的jar包:spring-aop-4.2.4.RELEASE.jar
组件类扫描路径
如果在包中指定了注解扫描的路径,则在该路径下如果出现以下注解都会被加载进spring创建bean
@Component 通用注解 都可用(默认bean名称以类名小写开头,可自定义)
@Named 同上
@Repository 持久层注解组件
@Service 业务层组件注解
@Controller 控制层组件注解
@Component
例:给Person加上@Component注解
@Component
public class Person {
private String name;
private Integer age;
//构造方法等方法略
...
}
新建testAnnotation方法并测试:
@Test
public void testAnnotation(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person=ctx.getBean("person",Person.class);
System.out.println(person);
}
控制台输出:
Person [name=null, age=null]
由此可见,已经为Person类创建了Bean,但是并没有给属性注入值。
同样可以使用其他注解给相应的类添加注解,例如,给持久层dao添加注解并指定bean名称:
@Repository("personDao")//相当于在配置文件中 <bean id="personDao" class="……"></bean>
public class PersonDaoImpl implements PersonDao{
private Person person=new Person();
@Override
public void msg() {
System.out.println(person);
}
}
在test中测试:
@Test
public void testAnnotation(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonDao person=ctx.getBean("personDao",PersonDao.class);
person.msg();
}
控制台输出:
Person [name=null, age=null]
指定依赖注入关系注解
@Autowired/@Qualifier
处理构造器注入和setter注入
用法:
@Autowired :可以用于 Setter 方法、构造函数、字段,甚至普通方法,前提是方法必须有至少一个参数。
@Qualifier :当容器中存在多个 Bean 的类型与需要注入的参数类型相同时,注入将不能执行,可以使用@Qualifier 标注,提供一个 String 类型的值作为候选的 Bean 的名字
案例:使用注解完成bean的实例化和属性的注入,完成上述代码的解耦:
修改Person,使用注解@Value给属性注入值
@Component
public class Person {
@Value("二狗")
private String name;
@Value("18")
private Integer age;
//构造方法等方法略
...
}
修改PersonDaoImpl文件,添加@autowired注解:
@Repository("personDao")
public class PersonDaoImpl implements PersonDao{
@Autowired //自动装配,根据类名称去找相应的类来创建对象
private Person person;
@Override
public void msg() {
System.out.println(person);
}
}
直接测试刚才的方法,使用了注解完成自动装配:
Person [name=二狗, age=18]
假设现在Spring容器中存在两个Person类型的bean :person和person1,则使用@Autowired无法完成自动装配,需要使用@Qualifier来指定bean的名称,例如:
@Repository("personDao")
public class PersonDaoImpl implements PersonDao{
@Autowired //自动装配,根据类名称去找相应的类来创建对象
@Qualifier("person")//当多个Person类型的bean存在时,可以指定自动装配的bean名称
private Person person;
@Override
public void msg() {
System.out.println(person);
}
}
@Inject/@Named
用法与同上,只不过需要额外导包
@Resource/@Name
只能处理setter注入
@Resource 相当于@Autowired
@Name的作用相当于@Qualifier
修改PersonService,使用@Service给业务层创建bean,使用@Resource 完成自动装配
@Service//@Component 业务层组件扫描
public class PersonService {
@Resource(name="personDao")//指定bean名称注入
private PersonDao personDao;
public void msg(){
personDao.msg();
}
}
修改测试方法为:
@Test
public void testAnnotation(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonDao person=ctx.getBean("personDaoImpl",PersonDao.class);
person.msg();
PersonService service=ctx.getBean("personService",PersonService.class);
service.msg();
}
测试结果为:
Person [name=二狗, age=18]
Person [name=二狗, age=18]
@Autowired和@Resource的区别
1)@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
2)@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用
3)@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
下一章,Spring AOP概述