基于注解的组件扫描——Spring IOC/DI(五)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34598667/article/details/83341675

上一章我们讲了无注解的自动装配:
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概述

猜你喜欢

转载自blog.csdn.net/qq_34598667/article/details/83341675