1. @Resource--手动注入
使用Field注入(用于注解方式),注入依赖对象可以采用手工装配或自动装配.在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果。
@Resource注解和@Autowired一样,同样也可以标注在字段或属性的setter方法上,但它默认按名称装配。名称可以通过@Resource的name属性指定,如果没有指定name属性,当注解标注在字段上时,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上时,即默认取属性名作为bean名称寻找依赖对象。
**注意:如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。 **
1). 创建项目并导包
导入Jar包:spring-beans-5.0.5.RELEASE.jar、spring-context-5.0.5.RELEASE.jar、spring-core-5.0.5.RELEASE.jar、spring-expression-5.0.5.RELEASE.jar、spring-aop-5.0.5.RELEASE.jar、
commons-logging-1.2.jar.(注:这里多了aop的jar包)
图1.png
2). 在src目录下创建bean.xml文件,并向beans节点中添加
<context:annotation-config/>
<?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: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">
<!-- 在java代码中使用@Autowired或@Resource注解方式进行装配。
@Autowired默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配
这个配置隐式注册了多个对注解进行解析处理的处理器:
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
-->
<context:annotation-config/>
</beans>
3). 在src目录下新建com.mazaiting.dao包,然后创建PersonDao接口
public interface PersonDao {
void add();
}
4). 创建com.mazaiting.dao.impl包,并创建实现PersonDao接口的PersonDaoImpl 实现类
public class PersonDaoImpl implements PersonDao {
@Override
public void add() {
System.out.println("执行PersonDaoImpl中的add()方法");
}
}
5). 创建com.mazaiting.service类,并创建PersonService接口
public interface PersonService {
void save();
}
6). 创建com.mazaiting.service.impl,并创建实现PersonService接口的PersonServiceImpl实现类
public class PersonServiceImpl implements PersonService {
private PersonDao personDao;
private String name;
public PersonServiceImpl() {}
public PersonServiceImpl(PersonDao personDao, String name) {
this.personDao = personDao;
this.name = name;
}
@Override
public void save() {
System.out.println("PersonServiceImpl--" + name);
personDao.add();
}
}
7). 在bean.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: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">
<!-- 在java代码中使用@Autowired或@Resource注解方式进行装配。
@Autowired默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配
这个配置隐式注册了多个对注解进行解析处理的处理器:
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
-->
<context:annotation-config/>
<bean id="personDao" class="com.mazaiting.dao.impl.PersonDaoImpl"></bean>
<bean id="personService" class="com.mazaiting.service.impl.PersonServiceImpl"></bean>
</beans>
8). 在PersonServiceImpl中添加注解
public class PersonServiceImpl implements PersonService {
@Resource private PersonDao personDao;
private String name;
public PersonServiceImpl() {}
public PersonServiceImpl(PersonDao personDao, String name) {
this.personDao = personDao;
this.name = name;
}
@Override
public void save() {
personDao.add();
}
}
9). 创建测试文件TestSpring
public class TestSpring {
@Test
public void test() {
// 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 创建对象
PersonService service = (PersonService) context.getBean("personService");
// 执行方法
service.save();
}
}
10). 打印结果
图2.png
11). 将bean.xml文件中
<bean id="personDao" class="com.mazaiting.dao.impl.PersonDaoImpl"></bean>
修改为
<bean id="personDaoTest" class="com.mazaiting.dao.impl.PersonDaoImpl"></bean>
然后执行测试代码,打印结果为:
图3.png
12). 修改PersonServiceImpl文件为
public class PersonServiceImpl implements PersonService {
// 1. 注解在变量上
// @Resource private PersonDao personDao;
// 2. 注解在set方法上
private PersonDao personDao;
@Resource
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
private String name;
public PersonServiceImpl() {}
public PersonServiceImpl(PersonDao personDao, String name) {
this.personDao = personDao;
this.name = name;
}
@Override
public void save() {
personDao.add();
}
}
执行结果:
图4.png
2. @Autowire注解完成属性装配
1). 将PersonServiceImpl内容修改为
public class PersonServiceImpl implements PersonService {
// 1. 注解在变量上
// @Resource private PersonDao personDao;
// // 2. 注解在set方法上
// private PersonDao personDao;
// @Resource
// public void setPersonDao(PersonDao personDao) {
// this.personDao = personDao;
// }
// 3. @Autowire注解
@Autowired private PersonDao personDao;
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public void save() {
personDao.add();
}
}
运行测试代码结果:
图5.png
注意:@Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如:
@Autowired(required=true) @Qualifier("personDaoxxxx") private PersonDao personDao;
required=true代表字段personDao必须要注入值,也即是说在Spring容器中根据类型找不到对应的bean,那就会报异常;required=false意味着在Spring容器中根据类型找不到对应的的bean,就会把该字段设为null。
2). 与@Qualifier结合使用
将PersonServiceImpl中的代码修改为
public class PersonServiceImpl implements PersonService {
// 1. 注解在变量上
// @Resource private PersonDao personDao;
// // 2. 注解在set方法上
// private PersonDao personDao;
// @Resource
// public void setPersonDao(PersonDao personDao) {
// this.personDao = personDao;
// }
// 3. @Autowire注解
@Autowired @Qualifier("personDaoTest") private PersonDao personDao;
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public void save() {
personDao.add();
}
}
执行测试代码结果:
图6.png
3. 依赖注入——自动装配依赖对象
示例:
<bean id="..." class="..." autowire="byType"/>
autowire属性取值如下:
- byType:按类型装配,可以根据属性的类型,在容器中寻找跟该类型匹配的bean。如果发现多个,那么将会抛出异常。如果没有找到,即属性值为null。
- byName:按名称装配,可以根据属性的名称,在容器中寻找跟该属性名相同的bean,如果没有找到,即属性值为null。
- constructor与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
- autodetect:通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。
1). 将PersonServiceImpl代码修改
public class PersonServiceImpl implements PersonService {
// 1. 注解在变量上
// @Resource private PersonDao personDao;
// // 2. 注解在set方法上
// private PersonDao personDao;
// @Resource
// public void setPersonDao(PersonDao personDao) {
// this.personDao = personDao;
// }
// 3. @Autowire注解
// @Autowired @Qualifier("personDaoTest") private PersonDao personDao;
// 4. 自动装配
private PersonDao personDao;
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public void save() {
personDao.add();
}
}
2). 修改bean.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: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">
<!-- 在java代码中使用@Autowired或@Resource注解方式进行装配。
@Autowired默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配
这个配置隐式注册了多个对注解进行解析处理的处理器:
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
-->
<context:annotation-config/>
<bean id="personDaoTest" class="com.mazaiting.dao.impl.PersonDaoImpl"></bean>
<!-- <bean id="personService" class="com.mazaiting.service.impl.PersonServiceImpl"></bean> -->
<bean id="personService" class="com.mazaiting.service.impl.PersonServiceImpl" autowire="byType"></bean>
</beans>
运行测试代码打印:
图7.png
3). 若将bean.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: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">
<!-- 在java代码中使用@Autowired或@Resource注解方式进行装配。
@Autowired默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配
这个配置隐式注册了多个对注解进行解析处理的处理器:
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
-->
<context:annotation-config/>
<bean id="personDaoTest" class="com.mazaiting.dao.impl.PersonDaoImpl"></bean>
<!-- <bean id="personService" class="com.mazaiting.service.impl.PersonServiceImpl"></bean> -->
<bean id="personService" class="com.mazaiting.service.impl.PersonServiceImpl" autowire="byName"></bean>
</beans>
则必须将其中的
<bean id="personDaoTest" class="com.mazaiting.dao.impl.PersonDaoImpl"></bean>
<bean id="personDao" class="com.mazaiting.dao.impl.PersonDaoImpl"></bean>
执行测试代码:
图8.png
4. Spring自动扫描和管理Bean
1). 使用XML的bean定义来配置组件时,在一个稍大的项目中,通常会有上百个组件,如果这些组件采用XML的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便。Spring2.5为我们引入了组件自动扫描机制,它可以在类路径底下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入进Spring容器中管理。它的作用和在XML文件中使用bean节点配置组件是一样的。要使用自动扫描机制,我们需要打开以下配置信息:
<?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: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.mazaiting" />
</beans>
其中<context:component-scan base-package="com.mazaiting" />这个配置隐式注册了多个对注解进行解析处理的处理器,包括<context:annotation-config/>该配置注册的处理器,也就是说写了<context:component-scan base-package="com.mazaiting" />配置,就不用写<context:annotation-config/>配置了,此外base-package为需要扫描的包(含子包)。
@Service用于标注业务层组件、 @Controller用于标注控制层组件(如Struts2中的action)、@Repository用于标注数据访问组件,即DAO组件。而@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
2). 修改bean.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: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">
<!-- 自动扫描和管理Bean配置 -->
<context:component-scan base-package="com.mazaiting"/>
</beans>
3). 修改PersonServiceImpl和PersonDaoImpl类内容
PersonServiceImpl.java
@Service
public class PersonServiceImpl implements PersonService {
private PersonDao personDao;
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public void save() {
personDao.add();
}
}
PersonDaoImpl.java
@Repository
public class PersonDaoImpl implements PersonDao {
@Override
public void add() {
System.out.println("执行PersonDaoImpl中的add()方法");
}
}
4). 修改测试代码
public class TestSpring {
@Test
public void test() {
// 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 创建对象
PersonService service = (PersonService) context.getBean("personServiceImpl");
PersonDao dao = (PersonDao) context.getBean("PersonDaoImpl");
System.out.println(service.toString());
System.out.println(dao.toString());
}
}
执行测试代码打印结果:
图9.png
5). 如果我们想使用按指定名称获取,可将PersonServiceImpl类的代码修改为:
I. 修改PersonServiceImpl.java文件
@Service("personService")
public class PersonServiceImpl implements PersonService {
private PersonDao personDao;
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public void save() {
personDao.add();
}
}
II. 修改测试代码如下:
public class TestSpring {
@Test
public void test() {
// 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 创建对象
PersonService service = (PersonService) context.getBean("personService");
PersonDao dao = (PersonDao) context.getBean("personDaoImpl");
System.out.println(service.toString());
System.out.println(dao.toString());
}
}
III. 执行测试代码,打印结果如下:
图10.png
5. 管理作用域
默认创建的对象作用域为SingleTon, 我们可以通过@Scope来管理作用域
1). 修改PersonServiceImpl.java文件
@Service("personService")
@Scope("prototype")
public class PersonServiceImpl implements PersonService {
private PersonDao personDao;
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public void save() {
personDao.add();
}
}
2). 修改测试代码
public class TestSpring {
@Test
public void test() {
// 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 创建对象
PersonService service1 = (PersonService) context.getBean("personService");
PersonService service2 = (PersonService) context.getBean("personService");
System.out.println(service1 == service2);
}
}
执行测试代码,打印结果:
图11.png
说明:prototype作用域意味着每次从Spring容器获取bean都是新的对象嘛。
3). 使用@PostConstruct和@PreDestroy来注解初始化方法和销毁当前类方法
修改PersonServiceImpl.java文件为:
@Service("personService")
public class PersonServiceImpl implements PersonService {
private PersonDao personDao;
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public void save() {
personDao.add();
}
@PostConstruct
public void init() {
System.out.println("初始化");
}
@PreDestroy
public void destroy() {
System.out.println("销毁");
}
}
修改测试代码为:
public class TestSpring {
@Test
public void test() {
// 加载配置文件
AbstractApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 创建对象
PersonService service1 = (PersonService) context.getBean("personService");
context.close();
}
}
执行测试代码,打印结果为:
图12.png