前言
在Spring的第二篇中主要讲解了Spring Core模块的使用IOC容器创建对象的问题,Spring Core模块主要是解决对象的创建和对象之间的依赖关系,因此本博文主要讲解如何使用IOC容器来解决对象之间的依赖关系!
回顾以前对象依赖
我们来看一下我们以前关于对象依赖,是怎么的历程
直接new对象
- 在最开始,我们是直接new对象给serice的userDao属性赋值...
 
class  UserService{
    UserDao userDao = new UserDao();
}写DaoFactory,用字符串来维护依赖关系
后来,我们发现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);
        }
    }
}- serivce
 
    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);DaoFactory读取配置文件
再后来,我们发现要修改Dao的实现类,还是得修改service层的源代码呀..于是我们就在DaoFactory中读取关于daoImpl的配置文件,根据配置文件来创建对象,这样一来,创建的是哪个daoImpl对service层就是透明的
DaoFactory
```java
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;
}
}
```
- service
 
    UserDao dao = DaoFactory.getInstance().createUserDao();Spring依赖注入
通过上面的历程,我们可以清晰地发现:对象之间的依赖关系,其实就是给对象上的属性赋值!因为对象上有其他对象的变量,因此存在了依赖...
Spring提供了好几种的方式来给属性赋值
- 1) 通过构造函数
 - 2) 通过set方法给属性注入值
 - 3) p名称空间
 - 4)自动装配(了解)
 - 5) 注解
 
搭建测试环境
- UserService中使用userDao变量来维护与Dao层之间的依赖关系
 UserAction中使用userService变量来维护与Service层之间的依赖关系
userDao
public class UserDao {
    public void save() {
        System.out.println("DB:保存用户");
    }
}- userService
 
public class UserService {
    
    private UserDao userDao; 
    public void save() {
        userDao.save();
    }
}- userAnction
 
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>- 测试:可以成功获取到userDao对象
 
        // 创建容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //得到service对象
        UserService userService = (UserService) ac.getBean("userService");通过set方法给属性注入值
我们这里也是测试service和dao层的依赖关系就好了...在service层通过set方法来把userDao注入到UserService中
- 为UserService添加set方法
 
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节点来给属性赋值
- 引用类型使用ref属性
 - 基本类型使用value属性
 
    <!--创建userDao对象-->
    <bean id="userDao" class="UserDao"/>
    <!--创建userService对象-->
    <bean id="userService" class="UserService">
        <property name="userDao" ref="userDao"/>
    </bean>- 测试:
 
内部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 名称空间注入属性值
p名称控件这种方式其实就是set方法的一种优化,优化了配置而已...p名称空间这个内容需要在Spring3版本以上才能使用...我们来看看:
applicationContext.xml配置文件:使用p名称空间
    <bean id="userDao" class="UserDao"/>
    
    <!--不用写property节点了,直接使用p名称空间-->
    <bean id="userService" class="UserService" p:userDao-ref="userDao"/>- 测试
 
自动装配
Spring还提供了自动装配的功能,能够非常简化我们的配置
自动装载默认是不打开的,自动装配常用的可分为两种:
- 根据名字来装配
 - 根据类型类装配
 
XML配置根据名字
applicationContext.xml配置文件:使用自动装配,根据名字
    <bean id="userDao" class="UserDao"/>
    <!--
        1.通过名字来自动装配
        2.发现userService中有个叫userDao的属性
        3.看看IOC容器中没有叫userDao的对象
        4.如果有,就装配进去
    -->
    <bean id="userService" class="UserService" autowire="byName"/>- 测试
 
XML配置根据类型
applicationContext.xml配置文件:使用自动装配,根据类型
值得注意的是:如果使用了根据类型来自动装配,那么在IOC容器中只能有一个这样的类型,否则就会报错!
    <bean id="userDao" class="UserDao"/>
    <!--
        1.通过名字来自动装配
        2.发现userService中有个叫userDao的属性
        3.看看IOC容器UserDao类型的对象
        4.如果有,就装配进去
    -->
    <bean id="userService" class="UserService" autowire="byType"/>- 测试:
 
我们这只是测试两个对象之间的依赖关系,如果我们有很多对象,我们也可以使用默认自动分配
使用注解来实现自动装配
@Autowired注解来实现自动装配:
- 可以在构造器上修饰
 - 也可以在setter方法上修饰
 - **来自java的@Inject的和@AutoWired有相同的功能**
 
如果没有匹配到bean,又为了避免异常的出现,我们可以使用required属性上设置为false。【谨慎对待】
测试代码
@Component public class UserService { private UserDao userDao ; @Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
顺利拿到userDao的引用
使用JavaConfig配置类实现对象依赖
在
- 第一种(测试不出来)
 
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);
    }
}- 我测试中只有通过这种方法才能拿到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进去就行了..
- UserService
 
public class UserService {
    private UserDao userDao ;
    public UserService() {
    }
    public UserService(UserDao userDao) {
    }
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}- Config
 
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