在Spring的第二篇中主要讲解了Spring Core模块的使用IOC容器建立对象的问题,Spring Core模块主要是解决对象的建立和对象之间的依赖关系,所以本博文主要讲解如何使用IOC容器来解决对象之间的依赖关系!java
咱们来看一下咱们之前关于对象依赖,是怎么的历程spring
class UserService{
UserDao userDao = new UserDao();
}
复制代码
后来,咱们发现service层牢牢耦合了dao层。咱们就写了DaoFactory,在service层只要经过字符串就可以建立对应的dao层的对象了。服务器
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层就是透明的app
DaoFactory函数
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提供了好几种的方式来给属性赋值优化
UserService中使用userDao变量来维护与Dao层之间的依赖关系ui
UserAction中使用userService变量来维护与Service层之间的依赖关系this
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的引用
在有两种方法(但我测试不出来,若是会的请在评论去告诉我.....)
import org.springframework.context.annotation.Bean;
@org.springframework.context.annotation.Configuration
public class Configuration {
@Bean()
public UserDao userDao() {
return new UserDao();
}
@Bean
public UserService userService() {
//直接调用@bean的方法
return new UserService(userDao());
}
}
复制代码
import org.springframework.context.annotation.Bean;
@org.springframework.context.annotation.Configuration
public class Configuration {
@Bean()
public UserDao userDao() {
return new UserDao();
}
@Bean
public UserService userService(UserDao userDao) {
//经过构造函数依赖注入
return new UserService(userDao);
}
}
复制代码
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
@org.springframework.context.annotation.Configuration
public class Configuration {
@Bean()
public UserDao userDao() {
return new UserDao();
}
@Bean(autowire = Autowire.BY_TYPE)
public UserService userService(UserDao userDao) {
return new UserService(userDao);
}
}
复制代码
public class Configuration {
@Bean()
public UserDao userDao() {
return new UserDao();
}
@Bean(autowire = Autowire.BY_TYPE)
public UserService userService() {
return new UserService(userDao());
}
}
复制代码
固然了,最简单直观的方法还有一种:在UserService中加入setUser()方法,那么只要set进去就好了..
public class UserService {
private UserDao userDao ;
public UserService() {
}
public UserService(UserDao userDao) {
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
复制代码
import org.springframework.context.annotation.Bean;
@org.springframework.context.annotation.Configuration
public class Config1 {
@Bean(name = "userDao")
public UserDao userDao() {
return new UserDao();
}
@Bean(name="userService")
public UserService userService() {
UserService userService = new UserService();
userService.setUserDao(userDao());
return userService;
}
}
复制代码
扩展阅读:
若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同窗,能够关注微信公众号:Java3y