前言

在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配置是可以混合使用的…


Spring第三篇【Core模块之对象依赖】的更多相关文章

  1. spring第三篇

    在昨天下午更新sprin第二篇中,叙述了将对象交给spring创建和管理,今天在spring第三篇中,主要写两个点一是spring的思想 二是spring中bean元素的属性配置. 1 spring思 ...

  2. (转).net程序员转战android第三篇---登录模块之静态登录

    这一篇我将分2个部分记录登录界面,第一部分是静态登录, 这部分将如何从界面布局.控件使用.文件关系.数据验证.登陆实现等5小块记录. 第二部分是动态登录,这块会基于上面的4小块,在数据验证不是静态数据 ...

  3. .net程序员转战android第三篇---登录模块之静态登录

    这一篇我将分2个部分记录登录界面,第一部分是静态登录, 这部分将如何从界面布局.控件使用.文件关系.数据验证.登陆实现等5小块记录. 第二部分是动态登录,这块会基于上面的4小块,在数据验证不是静态数据 ...

  4. SSH框架之Spring第三篇

    1.1 AOP概述 1.1.1 什么是AOP? AOP : 全称是Aspect Oriented Progamming既 : 面向切面编程.通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技 ...

  5. 初学Java ssh之Spring 第三篇

    在这篇中,我学习了依赖注入的两种方式:设值注入和构造注入. 在我们以前的思维中,如果调用一个类时,我们都需要将其手动实例化,当我们创建被调用的工作不需要我们完成时,这就是控制反转,当这个将被调用的实例 ...

  6. Node.js入门教程 第三篇 (模块及路由)

    Node.js的模块 Node.js的模块与传统面向对象的类(class)不完全相同.Node.js认为文件即模块,即一个文件是一个模块.单一文件一般只专注做一件事情,保证了代码的简洁性. 创建模块: ...

  7. Python笔记_第三篇_面向对象_8.对象属性和类属性及其动态添加属性和方法

    1. 对象属性和类属性. 我们之前接触到,在类中,我们一般都是通过构造函数的方式去写一些类的相关属性.在第一次介绍类的时候我们把一些属性写到构造函数外面并没有用到构造函数,其实当时在写的时候,就是在给 ...

  8. OpenCV2:总结篇 core模块

    一.cv::Mat 1.作用 cv::Mat表示图像类,用来操作图像和矩阵,它包含很多属性和方法 2.构造方法 cv::Mat image;  //cv::Mat image()      无参数构造 ...

  9. 死磕Spring之AOP篇 - Spring 事务详解

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

随机推荐

  1. Struts2.5的的环境搭建及跑通流程

    Struts2.5 struts是开源框架.使用Struts的目的是为了帮助我们减少在运用MVC设计模型来开发Web应用的时间.如果我们想混合使用Servlets和JSP的优点来建立可扩展的应用,st ...

  2. 【物联网云端对接-4】通过MQTT协议与百度云进行云端通信

    百度云的天工物联网服务目前包括:物接入.物解析.物管理.时序数据库和规则引擎等5大部分,本篇文章仅介绍物接入. 天工物联网的物接入,从开发者的角度来说相对有些复杂,需要多步操作才能实现一个云设备的创建 ...

  3. 抛开深层次底层,快速入门SpringMVC

    SpringMVC主要有三个核心部分组成,DispatcherServlet.Controller.ViewResolver.          DispatcherServlet:     请求输入 ...

  4. java中Object转String

      Object转为String的几种形式 在java项目的实际开发和应用中,常常需要用到将对象转为String这一基本功能.本文将对常用的转换方法进行一个总结.常用的方法有Object.toStri ...

  5. SUID SGID

    SUID 1.只作用在可执行二进制文件上,普通用户需要对该文件有x权限, 2.在执行该文件时,用户身份切换为文件owner: 3.执行完毕,切换回普通用户. 一.查找具有SUID权限的系统文件(-40 ...

  6. sed 实践案例 (不定期更新)

    删除每行第一个字符 sed -r 's/^.//g' /etc/passwd 删掉每行第二个字符 sed -r 's/^(.)(.)/\1/g' /etc/passwd 删掉每行最后一个字符 sed ...

  7. Linux中的定时任务at、crontab

    at at命令可以用来在某一时段执行一次任务,只会执行一次,不会重复执行. at命令是由atd服务来控制的,使用之前先查看atd服务是否正常: $ /etc/init.d/atd status * a ...

  8. CNAME关联githubPage域名及中文域名,创建个人网站

    对于前端开发来说,部署一个自己的个人网站部署服务器等比较麻烦,如果只是做静态页面的展示GitHubPage完全够用,而且有300M免费的空间,完全满足需求. 首先你要有GitHubPage项目,具体怎 ...

  9. Andrew Ng机器学习课程笔记--week8(K-means&PCA)

    Unsupervised Learning 本周我们讲学习非监督学习算法,会学习到如下概念 聚类(clustering) PCA(Principal Componets Analysis主成分分析), ...

  10. Oracle异常汇总

    持续更新中,可参见https://hnuhell.gitbooks.io/oracle_errmg/content/或https://hnuhell.github.io/Oracle_ERRMG/上的 ...