zoukankan      html  css  js  c++  java
  • Spring第三篇【Core模块之对象依赖】

    前言

    在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

    
    
    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的引用

    这里写图片描述

    注解

    自从jdk5有了注解这个新特性,我们可以看到Struts2框架、Hibernate框架都支持使用注解来配置信息…

    通过注解来配置信息就是为了简化IOC容器的配置,注解可以把对象添加到IOC容器中、处理对象依赖关系,我们来看看怎么用吧:

    使用注解步骤:

    • 1)先引入context名称空间
      • xmlns:context=”http://www.springframework.org/schema/context”
    • 2)开启注解扫描器
      • <context:component-scan base-package=""></context:component-scan>
      • 也可以通过自定义扫描类以@CompoentScan修饰来扫描IOC容器的bean对象
    
    //表明该类是配置类
    @Configuration
    
    //启动扫描器,扫描bb包下的
        //也可以指定多个基础包
        //也可以指定类型
    @ComponentScan("bb")
    public class AnnotationScan {
    
    }

    在使用@ComponentScan()这个注解的时候,在测试类上需要@ContextConfiguration这个注解来加载配置类…

    • @ContextConfiguration这个注解又在Spring的test包下..

    创建对象以及处理对象依赖关系,相关的注解:

    • @ComponentScan扫描器
    • @Configuration表明该类是配置类
    • @Component 指定把一个对象加入IOC容器—>@Name也可以实现相同的效果【一般少用】
    • @Repository 作用同@Component; 在持久层使用
    • @Service 作用同@Component; 在业务逻辑层使用
    • @Controller 作用同@Component; 在控制层使用
    • @Resource 依赖关系
      • 如果@Resource不指定值,那么就根据类型来找,相同的类型在IOC容器中不能有两个
      • 如果@Resource指定了值,那么就根据名字来找

    测试代码

    • UserDao
    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:保存用户");
        }
    
    
    }
    
    • userService
    
    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();
        }
    }
    
    • userAction
    
    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配置是可以混合使用的…


  • 相关阅读:
    month(字段)、year(字段)
    简单音乐播放器实现
    Mp3音乐文件列表实现
    读取SD卡中所有MP3文件
    java基础复习 之 多态
    JavaWeb学习过程 之c3p0的使用
    JavaWeb学习过程 之MVC模式下的查询
    行转列:总结
    如何快速禁用约束 (解决ORA-O2266问题)
    PLSQL Developer 11 使用技巧(持续更新)
  • 原文地址:https://www.cnblogs.com/zhong-fucheng/p/7202954.html
Copyright © 2011-2022 走看看