为了账号安全,请及时绑定邮箱和手机立即绑定

Spring【依赖注入】就是这么简单

标签:
Java

前言

在Spring的第二篇中主要讲解了Spring Core模块的使用IOC容器创建对象的问题,Spring Core模块主要是解决对象的创建和对象之间的依赖关系,因此本博文主要讲解如何使用IOC容器来解决对象之间的依赖关系


回顾以前对象依赖

我们来看一下我们以前关于对象依赖,是怎么的历程


直接new对象

  • 在最开始,我们是直接new对象给service的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方法给属性注入值


  1. 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的依赖关系就好了....在service中加入一个构造函数,参数就是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。【谨慎对待】

    • 测试代码

    @Componentpublic 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.Configurationpublic 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;
        }
    
    }

     作者:Java3y                    

    来源:https://my.oschina.net/u/3777556/blog/1634483


    点击查看更多内容
    TA 点赞

    若觉得本文不错,就分享一下吧!

    评论

    作者其他优质文章

    正在加载中
    • 推荐
    • 评论
    • 收藏
    • 共同学习,写下你的评论
    感谢您的支持,我会继续努力的~
    扫码打赏,你说多少就多少
    赞赏金额会直接到老师账户
    支付方式
    打开微信扫一扫,即可进行扫码打赏哦
    今天注册有机会得

    100积分直接送

    付费专栏免费学

    大额优惠券免费领

    立即参与 放弃机会
    意见反馈 帮助中心 APP下载
    官方微信

    举报

    0/150
    提交
    取消