标签:
Spring框架是目前各大Java开发者追捧的框架之一,相信对于大家来说并不陌生,Spring之所以这么流行,少不了他的两大核心技术IOC和IOP。我们这里重点讲述Spring框架的IOC技术。在我们平 常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一 管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中。 依赖注入的另一种说法是“控制反转”,通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员,而控制反转是指new实例工作不由我们程序 员来做而是交给spring容器来做。
在Spring容器中为一个bean配置依赖注入有三种方式:
1) 使用属性的setter方法注入 这是最常用的方式;
2) 使用构造器注入;
3) 使用Filed注入(用于注解方式)
准备工作
Spring是开源框架,在开始我们的实例之前,需要IOC必备的开发包。
1.使用属性的setter方法注入
首先要配置被注入的bean,在该bean对应的类中,应该有要注入的对象属性或者基本数据类型的属性,并且拥该属性或数据类型的set方法。
1 //我们首先定义一个UserDao的接口 2 interface UserDao { 3 4 public void say(); 5 } 6 7 8 //定义一个类,并且实现我们的UserDao接口 9 class UserDaoImpl implements UserDao { 10 11 @Override 12 public void say() { 13 System.out.println("我是UserDaoImpl类,我是实现了UserDao接口,我是通过set方法创建的。"); 14 } 15 } 16 17 18 class UserService { 19 20 //注意这里定义的userDao是接口的引用。当然也可以是 UserDaoImpl userDao 。 21 //我们提倡用前者,面向接口编程,来降低我们代码的耦合度!!! 22 private UserDao userDao; 23 24 public void setUserDao(UserDao userDAO) { 25 this.userDao = userDAO; 26 } 27 28 public void fun() { 29 30 System.out.println("我要执行真正的逻辑操作了"); 31 32 //请注意,在整个过程中,我们并没有手动实例化过userDao对象,而是让Spring容器为我们实例化的 33 userDao.say(); 34 } 35 } 36 37 38 public class SetTest { 39 40 public static void main(String[] args) { 41 ApplicationContext context = new ClassPathXmlApplicationContext("set.xml"); 42 43 // 2、从容器中获取Bean 44 UserService userDao = context.getBean("userService", UserService.class); 45 46 // 3、执行业务逻辑 47 userDao.fun(); 48 } 49 }
下面我们来看一下我们的set.xml是如何配置的
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 4 xsi:schemaLocation=" 5 http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 7 http://www.springframework.org/schema/context 8 http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 9 10 <bean id="userService" class="UserService"> 11 <!--依赖注入,配置当前类中相应的属性,该属性必须有对应的set方法--> 12 <property name="userDao" ref="userDao"></property> 13 </bean> 14 <bean id="userDao" class="UserDaoImpl"></bean> 15 16 </beans>
不知道你对上述配置文件是否了解,我们就先简单的介绍一下,<bean>代表一个java对象,id="userService" class="UserService" ,则相当于我们平时写Java代码的UserService userService 。<property>则是为配置的对象设置属性。<property name="userDao" ref="userDao"></property> 在这个标签中 name 代表着 class="UserService" 这个类的属性,ref 则是指向已经当经定义好的bean对象。请特别留意代码中的那句注释“<!--依赖注入,配置当前类中相应的属性,该属性必须有对应的set方法-->”,否则运行时会报错。特别注意了哦!! 在这里我们的class引入的是类的路径: 包名.类型 ,例如在 在com包下有类 Test,则class = "com.Test" 。特别注意了哦。
有时候,我们希望产生对象是通过我们写工厂方法产生,并且又希望能通过Spring来产生对象。
1.1静态工厂注入的处理
静态工厂顾名思义,就是通过调用静态工厂的方法来获取自己需要的对象,为了让spring管理所有对象,我们不能直接通过"工程类.静态方法()"来获取对象,
而是依然通过Spring注入的形式获取。
下面我们来看一个这样的例子
1 //我们首先定义一个UserDao的接口
2 interface UserDao {
3
4 public void say();
5 }
6
7 //定义一个类,并且实现我们的UserDao接口
8 class UserDaoImpl implements UserDao {
9
10 @Override
11 public void say() {
12 System.out.println("我是UserDaoImpl类,我是实现了UserDao接口,我是通过工厂的静态方法产生的");
13 }
14 }
15
16 //添加静态工厂
17 class DaoFactory {
18 //静态工厂
19 public static final UserDao getStaticFactoryDaoImpl(){
20 return new UserDaoImpl();
21 }
22 }
23
24 class UserService {
25
26 private UserDao userDao;
27
28 public void setUserDao(UserDao userDao) {
29 this.userDao = userDao;
30 }
31
32 public void fun() {
33 userDao.say();
34 }
35 }
36
37 public class FactoryStaticsTest {
38
39 public static void main(String[] args) {
40
41 ApplicationContext context = new ClassPathXmlApplicationContext("factory.statics.xml");
42
43 // 2、从容器中获取Bean
44 UserService userDao = context.getBean("userService", UserService.class);
45
46 // 3、执行业务逻辑
47 userDao.fun();
48 }
49
50 }
我们看一下 factory.statics.xml配置文件的配置
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
4 xsi:schemaLocation="
5 http://www.springframework.org/schema/beans
6 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
7 http://www.springframework.org/schema/context
8 http://www.springframework.org/schema/context/spring-context-3.0.xsd">
9
10 <bean id="userService" class="factory.statics.UserService">
11 <!--依赖注入,配置当前类中相应的属性,该属性必须有对应的set方法-->
12 <property name="userDao" ref="userDao"></property>
13 </bean>
14 <bean id="userDao" class="factory.statics.DaoFactory"
15 factory-method="getStaticFactoryDaoImpl"></bean>
16 </beans>
1.2 实例工厂的方法注入
实例工厂的意思是获取对象实例的方法不是静态的,所以你需要首先new工厂类,再调用普通的实例方法。(PS: 先有工厂对象,在通过工厂的对象来产生我们的业务逻辑对象。)
1 //我们首先定义一个UserDao的接口
2 interface UserDao {
3
4 public void say();
5 }
6
7 //定义一个类,并且实现我们的UserDao接口
8 class UserDaoImpl implements UserDao {
9 @Override
10 public void say() {
11 System.out.println("我是UserDaoImpl类,我是实现了UserDao接口,我是通过工厂的实例方法产生的");
12 }
13 }
14
15 //添加工厂类
16 class DaoFactory {
17
18 //产生UserDao对象
19 public UserDao getFactoryDaoImpl(){
20 return new UserDaoImpl();
21 }
22 }
23
24 class UserService {
25
26 private UserDao userDao;
27
28 public void setUserDao(UserDao userDao) {
29 this.userDao = userDao;
30 }
31
32 public void fun() {
33 userDao.say();
34 }
35 }
36
37 public class FactoryObject {
38
39 public static void main(String[] args) {
40 ApplicationContext context = new ClassPathXmlApplicationContext("factory.object.xml");
41
42 // 2、从容器中获取Bean
43 UserService userDao = context.getBean("userService", UserService.class);
44
45 // 3、执行业务逻辑
46 userDao.fun();
47 }
48 }
下面我们来看一下 factory.object.xml 配置文件的配置
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
4 xsi:schemaLocation="
5 http://www.springframework.org/schema/beans
6 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
7 http://www.springframework.org/schema/context
8 http://www.springframework.org/schema/context/spring-context-3.0.xsd">
9
10 <bean id="userService" class="factory.object.UserService">
11 <!--依赖注入,配置当前类中相应的属性,该属性必须有对应的set方法-->
12 <property name="userDao" ref="userDao"></property>
13 </bean>
14 <bean id="daoFactory" class="factory.object.DaoFactory"></bean>
15 <bean id="userDao" factory-bean="daoFactory"
16 factory-method="getFactoryDaoImpl"> </bean>
17 </beans>
2.使用构造器注入
使用构造器注入方式,不用为该类的属性属性设置setter方法,但是需要生成该类的相应的构造方法构造方法。
1 //我们首先定义一个UserDao的接口 2 interface UserDao { 3 4 public void say(); 5 } 6 7 //定义一个类,并且实现我们的UserDao接口 8 class UserDaoImpl implements UserDao { 9 @Override 10 public void say() { 11 System.out.println("我是UserDaoImpl类,我是实现了UserDao接口,我是通过构造方法创建的。"); 12 } 13 } 14 15 class UserService { 16 17 private UserDao userDao; 18 19 public UserService(UserDao userDao){ 20 this.userDao = userDao; 21 } 22 23 public void fun() { 24 userDao.say(); 25 } 26 } 27 28 29 public class ConstructorTest { 30 31 public static void main(String[] args) { 32 33 ApplicationContext context = new ClassPathXmlApplicationContext("construct.xml"); 34 35 // 2、从容器中获取Bean 36 UserService userDao = context.getBean("userService", UserService.class); 37 38 // 3、执行业务逻辑 39 userDao.fun(); 40 } 41 42 }
下面我们看一下 construct.xml 配置文件是怎么写的
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation=" 6 http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 10 11 <bean id="userService" class="constructor.UserService"> 12 <!--创建构造器注入,如果主类有带参的构造方法则需添加此配置 --> 13 <constructor-arg index="0" ref="userDao"></constructor-arg> 14 </bean> 15 <bean name="userDao" class="constructor.UserDaoImpl"></bean> 16 </beans>
3.使用字段(Filed)注入(用注解方式)
在Spring中,注入依赖对象可以采用手工装配或自动装配,在实际应用开发中建议使用手工装配,因为自动装配会产生许多未知情况,开发人员无法预见最终的装配结果。
手工装配依赖对象又分为两种方式:
一种是在XML文件中,通过在bean节点下配置;如上面讲到的使用属性的setter方法注入依赖对象和使用构造器方法注入依赖对象都是这种方式。
另一种就是在java代码中使用注解的方式进行装配,在代码中加入@Resource或者@Autowired
怎样使用注解的方式来为某个bena注入依赖对象呢?
首先,我们需要在Spring容器的配置文件applicationContext.Xml文件中配置以下信息,该信心是一个Spring配置文件的模板:
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
">
</beans>
注意:只有配置了红色部分的代码 才可以引入注解的命名空间,否则报错。 以上的配置隐式的注册了多个对注释进行解析的处理 器:AutowiredAnnotationBeanPostProcessor、 CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 等。
其次,在配置文件中打开<context:annotation-config>节点,告诉Spring容器可以用注解的方式注入依赖对象;其在配置文件中的代码如下:
<beans>
……
<context:annotation-config></context:annotation-config>
……
</beans>
第三,在配置文件中配置bean对象,如下:
<bean id="userDao" class="annotation.manul.UserDaoImpl"></bean>
<bean id="userService" class="annotation.manul.UserService"></bean>
下面我们来看一个注解注入的例子
1 interface UserDao { 2 3 void say(); 4 } 5 6 7 class UserDaoImpl implements UserDao { 8 @Override 9 public void say() { 10 System.out.println("I am created by manual annotation! + UserDaoImpl"); 11 } 12 } 13 14 class UserDaoImplEx implements UserDao { 15 16 @Override 17 public void say() { 18 System.out.println("I am created by manual annotation! + UserDaoImplEx!!!!!"); 19 } 20 } 21 22 class UserService { 23 24 @Resource(name="userDao") 25 private UserDao userDao = null; 26 27 public UserDao getUserDao() { 28 return userDao; 29 } 30 31 //在该属性的set方法上添加对应的方法,也能达到相同的效果。 32 /*@Resource(name="userDao") 33 public void setUserDa(UserDao userDao) { 34 this.userDao = userDao; 35 }*/ 36 37 public void fun() { 38 userDao.say(); 39 } 40 } 41 42 public class AnnotationManulTest { 43 44 public static void main(String[] args) { 45 46 ApplicationContext context = new ClassPathXmlApplicationContext( 47 "applicationContext.xml"); 48 49 // 2、从容器中获取Bean 50 51 UserService userDao = context.getBean("userService", UserService.class); 52 53 // 3、执行业务逻辑 54 userDao.fun(); 55 56 } 57 58 }
下面我们来看一下applicationContext.xml文件的配置
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 4 xsi:schemaLocation=" 5 http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 7 http://www.springframework.org/schema/context 8 http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 9 <!-- 打开<context:annotation-config>节点,告诉Spring容器可以用注解的方式注入依赖对象 --> 10 <context:annotation-config></context:annotation-config> 11 <context:component-scan base-package="annotation.manul" /> 12 13 <!-- <bean id="userDaoEx" class="annotation.manul.UserDaoImplEx"></bean> 14 <bean id="userDao" class="annotation.manul.UserDaoImpl"></bean> 15 <bean id="userService" class="annotation.manul.UserService"></bean> --> 16 17 </beans>
其中,在Java代码中可以使用@Autowired或@Resource注解方式进行Spring的依赖注入。两者的区别是:@Autowired默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean时,才会按类型装配。
比如:我们用@Autowired为上面的代码UserDAO接口的实例对象进行注解,它会到Spring容器中去寻找与UserDAO对象相匹配的类型,如果找到该类型则将该类型注入到userdao字段中;
如果用@Resource进行依赖注入,它先会根据指定的name属性去Spring容器中寻找与该名称匹配的类型,例如:@Resource(name="userDao"),如果没有找到该名称,则会按照类型去寻找,找到之后,会对字段userDao进行注入。
通常我们使用@Resource。
使用注解注入依赖对象不用再在代码中写依赖对象的setter方法或者该类的构造方法,并且不用再配置文件中配置大量的依赖对象,使代码更加简洁,清晰,易于维护。
在Spring IOC编程的实际开发中推荐使用注解的方式进行依赖注入。
Spring中提供了自动装配依赖对象的机制,但是在实际应用中并不推荐使用自动装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果。
自动装配是在配置文件中实现的,如下:
<bean id="***" class="***" autowire="byType">
只需要配置一个autowire属性即可完成自动装配,不用再配置文件中写<property>,但是在类中还是要生成依赖对象的setter方法。
Autowire的属性值有如下几个:
· byType 按类型装配 可以根据属性类型,在容器中寻找该类型匹配的bean,如有多个,则会抛出异常,如果没有找到,则属性值为null;
· byName 按名称装配 可以根据属性的名称在容器中查询与该属性名称相同的bean,如果没有找到,则属性值为null;
· constructor 与byType方式相似,不同之处在与它应用于构造器参数,如果在容器中没有找到与构造器参数类型一致的bean,那么将抛出异常;
· autodetect 通过bean类的自省机制(introspection)来决定是使用constructor还是byType的方式进行自动装配。如果发现默认的构造器,那么将使用byType的方式。
标签:
原文地址:http://www.cnblogs.com/yfyzy/p/4657141.html