在Spring的第二篇中主要讲解了Spring Core模块的使用IOC容器建立对象的问题,Spring Core模块主要是解决对象的建立和对象之间的依赖关系,所以本博文主要讲解如何使用IOC容器来解决对象之间的依赖关系!php
咱们来看一下咱们之前关于对象依赖,是怎么的历程java
class UserService{ UserDao userDao = new UserDao(); }
后来,咱们发现service层牢牢耦合了dao层。咱们就写了DaoFactory,在service层只要经过字符串就可以建立对应的dao层的对象了。spring
DaoFactory服务器
public class DaoFactory { private static final DaoFactory factory = new DaoFactory(); private DaoFactory(){} public static DaoFactory getInstance(){ return factory; } public <T> T createDao(String className,Class<T> clazz){ try{ T t = (T) Class.forName(className).newInstance(); return t; }catch (Exception e) { throw new RuntimeException(e); } } }
private CategoryDao categoryDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.CategoryDAOImpl", CategoryDao.class); private BookDao bookDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.BookDaoImpl", BookDao.class); private UserDao userDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.UserDaoImpl", UserDao.class); private OrderDao orderDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.OrderDaoImpl", OrderDao.class);
再后来,咱们发现要修改Dao的实现类,仍是得修改service层的源代码呀..因而咱们就在DaoFactory中读取关于daoImpl的配置文件,根据配置文件来建立对象,这样一来,建立的是哪一个daoImpl对service层就是透明的markdown
DaoFactoryapp
public class DaoFactory { private UserDao userdao = null; private DaoFactory(){ try{ InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties"); Properties prop = new Properties(); prop.load(in); String daoClassName = prop.getProperty("userdao"); userdao = (UserDao)Class.forName(daoClassName).newInstance(); }catch (Exception e) { throw new RuntimeException(e); } } private static final DaoFactory instance = new DaoFactory(); public static DaoFactory getInstance(){ return instance; } public UserDao createUserDao(){ return userdao; } }
UserDao dao = DaoFactory.getInstance().createUserDao();
经过上面的历程,咱们能够清晰地发现:对象之间的依赖关系,其实就是给对象上的属性赋值!由于对象上有其余对象的变量,所以存在了依赖…框架
Spring提供了好几种的方式来给属性赋值函数
UserAction中使用userService变量来维护与Service层之间的依赖关系测试
userDao优化
public class UserDao { public void save() { System.out.println("DB:保存用户"); } }
public class UserService { private UserDao userDao; public void save() { userDao.save(); } }
public class UserAction { private UserService userService; public String execute() { userService.save(); return null; } }
其实咱们在讲解建立带参数的构造函数的时候已经讲过了…咱们仍是来回顾一下呗..
咱们测试service和dao的依赖关系就行了….在serice中加入一个构造函数,参数就是userDao
public UserService(UserDao userDao) { this.userDao = userDao; //看看有没有拿到userDao System.out.println(userDao); }
applicationContext.xml配置文件
<!--建立userDao对象--> <bean id="userDao" class="UserDao"/> <!--建立userService对象--> <bean id="userService" class="UserService"> <!--要想在userService层中可以引用到userDao,就必须先建立userDao对象--> <constructor-arg index="0" name="userDao" type="UserDao" ref="userDao"></constructor-arg> </bean>
// 建立容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); //获得service对象 UserService userService = (UserService) ac.getBean("userService");
咱们这里也是测试service和dao层的依赖关系就行了…在service层经过set方法来把userDao注入到UserService中
public class UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; //看看有没有拿到userDao System.out.println(userDao); } public void save() { userDao.save(); } }
applicationContext.xml配置文件:经过property节点来给属性赋值
<!--建立userDao对象--> <bean id="userDao" class="UserDao"/> <!--建立userService对象--> <bean id="userService" class="UserService"> <property name="userDao" ref="userDao"/> </bean>
咱们刚才是先建立userDao对象,再由userService对userDao对象进行引用…咱们还有另外一种思惟:先建立userService,发现userService须要userDao的属性,再建立userDao…咱们来看看这种思惟方式是怎么配置的:
applicationContext.xml配置文件:property节点内置bean节点
<!-- 1.建立userService,看到有userDao这个属性 2.而userDao这个属性又是一个对象 3.在property属性下又内置了一个bean 4.建立userDao --> <bean id="userService" class="UserService"> <property name="userDao"> <bean id="userDao" class="UserDao"/> </property> </bean>
咱们发现这种思惟方式和服务器访问的执行顺序是同样的,可是若是userDao要屡次被其余service使用的话,就要屡次配置了…
p名称控件这种方式其实就是set方法的一种优化,优化了配置而已…p名称空间这个内容须要在Spring3版本以上才能使用…咱们来看看:
applicationContext.xml配置文件:使用p名称空间
<bean id="userDao" class="UserDao"/> <!--不用写property节点了,直接使用p名称空间--> <bean id="userService" class="UserService" p:userDao-ref="userDao"/>
Spring还提供了自动装配的功能,可以很是简化咱们的配置
自动装载默认是不打开的,自动装配经常使用的可分为两种:
applicationContext.xml配置文件:使用自动装配,根据名字
<bean id="userDao" class="UserDao"/> <!-- 1.经过名字来自动装配 2.发现userService中有个叫userDao的属性 3.看看IOC容器中没有叫userDao的对象 4.若是有,就装配进去 --> <bean id="userService" class="UserService" autowire="byName"/>
applicationContext.xml配置文件:使用自动装配,根据类型
值得注意的是:若是使用了根据类型来自动装配,那么在IOC容器中只能有一个这样的类型,不然就会报错!
<bean id="userDao" class="UserDao"/> <!-- 1.经过名字来自动装配 2.发现userService中有个叫userDao的属性 3.看看IOC容器UserDao类型的对象 4.若是有,就装配进去 --> <bean id="userService" class="UserService" autowire="byType"/>
咱们这只是测试两个对象之间的依赖关系,若是咱们有不少对象,咱们也能够使用默认自动分配
@Autowired注解来实现自动装配:
若是没有匹配到bean,又为了不异常的出现,咱们可使用required属性上设置为false。【谨慎对待】
@Component public class UserService { private UserDao userDao ; @Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
顺利拿到userDao的引用
自从jdk5有了注解这个新特性,咱们能够看到Struts2框架、Hibernate框架都支持使用注解来配置信息…
经过注解来配置信息就是为了简化IOC容器的配置,注解能够把对象添加到IOC容器中、处理对象依赖关系,咱们来看看怎么用吧:
使用注解步骤:
<context:component-scan base-package=""></context:component-scan>
//代表该类是配置类 @Configuration //启动扫描器,扫描bb包下的 //也能够指定多个基础包 //也能够指定类型 @ComponentScan("bb") public class AnnotationScan { }
在使用@ComponentScan()这个注解的时候,在测试类上须要@ContextConfiguration这个注解来加载配置类…
建立对象以及处理对象依赖关系,相关的注解:
package aa; import org.springframework.stereotype.Repository; /** * Created by ozc on 2017/5/10. */ //把对象添加到容器中,首字母会小写 @Repository public class UserDao { public void save() { System.out.println("DB:保存用户"); } }
package aa; import org.springframework.stereotype.Service; import javax.annotation.Resource; //把UserService对象添加到IOC容器中,首字母会小写 @Service public class UserService { //若是@Resource不指定值,那么就根据类型来找--->UserDao....固然了,IOC容器不能有两个UserDao类型的对象 //@Resource //若是指定了值,那么Spring就在IOC容器找有没有id为userDao的对象。 @Resource(name = "userDao") private UserDao userDao; public void save() { userDao.save(); } }
package aa; import org.springframework.stereotype.Controller; import javax.annotation.Resource; /** * Created by ozc on 2017/5/10. */ //把对象添加到IOC容器中,首字母会小写 @Controller public class UserAction { @Resource(name = "userService") private UserService userService; public String execute() { userService.save(); return null; } }
package aa; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by ozc on 2017/5/10. */ public class App { public static void main(String[] args) { // 建立容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("aa/applicationContext.xml"); UserAction userAction = (UserAction) ac.getBean("userAction"); userAction.execute(); } }
注解和XML配置是能够混合使用的…