Spring IOC
前言
我们在实现类和类之间的依赖的时候,通常需要new需要被调用的类。
比如;Service层 New 了一个Dao层的类, 可以考虑用工厂,利用factroy来得到dao层的具体实现类,但工厂模式的缺陷只能创建一个对象,这个时候可以考虑使用抽象工厂,可以创建多个对象。
spring用IOC来做这个事情,spring容器来定位对象,创建好后提供可使用的对象,并且还可以管理对象和对象之间的依赖关系。
先看一下工厂模式。
工厂模式
隐藏了具体创建ItemDao4OracleImpl的过程,在Service层调用的时候,直接找相应的类创建工厂就可以实现。
但是如果想要修改成Mysql的数据库,Service就需要对代码进行修改,因为当初是直接New 的具体的创建Oracle的工厂类,这就违背了对修改关闭,对拓展开发的原则。
这个时候可以通过反射来实现。
反射调用:
用反射来代替普通的new调用工厂类
把工厂类配置到xml文件中,通过读取xml文件,后获取类交给反射工厂进行实例化,如果修改只修改配置文件即可,如图:
会发现这样也省去了new具体的类,变的更灵活可配,只要给反射工厂传入你需要调用类名,就可以实现调用,给你实例化好,不需要我们进行实例化。
那可不可以让不同层的类和类之间的调用都采用这样的方式。也就是实现创建多个类。
抽象工厂
可以通过一个中间的工厂,把需要实例化的类都交给它,它可以根据需要创建多个类
/**
* 抽象工厂,主要创建两个系列的产品:
* 1、Manager系列
* 2、Dao系列产品
* @author Administrator
*
*/
public class BeanFactory {
/*单例模式*/
private static BeanFactory instance = new BeanFactory();
public static BeanFactory getInstance() {
return instance;
}
private final String beansConfigFile = "beans-config.xml";
//保存Service相关对象
private Map serviceMap = new HashMap();
//保存Dao相关对象
private Map daoMap = new HashMap();
//存储 文件中的值
private Document doc;
/*获取到xml文件中的内容存储到document中*/
private BeanFactory() {
try {
doc = new SAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(beansConfigFile));
} catch (DocumentException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
/**
* 根据产品编号取得Service系列产品
* @param
* @return
*/
public synchronized Object getServiceObject(Class c){
return "省略--service和getDaoObject一样";
}
/**
* 根据产品编号取得Service系列产品
* @param
* @return
*/
public synchronized Object getDaoObject(Class c){
//如果存在相关对象实例,返回
if (daoMap.containsKey(c.getName())) {
return daoMap.get(c.getName());
}
// 如果没有实例化过,----取出传入的类名----对应doc中的id----找到class----反射进行实例化----存入map
Element beanElt = (Element)doc.selectSingleNode("//dao[@id=\\\"\" + c.getName() + \"\\\"]");
String className = beanElt.attributeValue("class");
Object dao = null;
try {
dao = Class.forName(className).newInstance();
//将创建好多的对象放到Map中
daoMap.put(c.getName(), dao);
} catch (Exception e) {
throw new RuntimeException();
}
return dao;
}
}
Spring IOC
spring框架把类似这样的思想的代码整合起来,专门去做了这样的封装,来实现管理对象的目的。我们只需通过使用spring的配置文件applicationContext.xml来实现它提供的服务。
使用方式有两种:
第一种:不使用注解:
在applicationContext.xml中,每个bean标签都相当于注入springIOC容器中的类
在代码中UserManageImpl是需要调用dao层下userDao4Oracle类下的方法,也就是userManage依赖于userDao4Oracle,
如下,可以直接在<bean id="userManager" class="com.bjpowernode.spring.manager.UserManagerImpl"></bean>中注入<constructor-arg ref="usrDao4Oracle"/>来表示他们的依赖关系。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="userDao4Mysql" class="com.bjpowernode.spring.dao.UserDao4MySqlImpl"/>
<bean id="usrDao4Oracle" class="com.bjpowernode.spring.dao.UserDao4OracleImpl"/>
<bean id="userManager" class="com.bjpowernode.spring.manager.UserManagerImpl">
<!--
<constructor-arg ref="userDao4Mysql"/>
-->
<constructor-arg ref="usrDao4Oracle"/>
<!-- <property name="userDao" ref="usrDao4Oracle"/>-->
</bean>
</beans>
在代码中:可以不去new UserDao ,就可以直接调用userDao.addUser(~,~)
PS:另外看代码中的注释,可以通过另一种方式,实现注入。和xml文件中的配置相互匹配即可。
public class UserManagerImpl implements UserManager {
// 使用spring已经实例化好并注入的userDao
private UserDao userDao;
public UserManagerImpl(UserDao userDao) {
this.userDao = userDao;
}
public void addUser(String username, String password) {
userDao.addUser(username, password);
}
/*如果xml不采用constructor-arg构造方法注入,
需要配置文件中写<property name="userDao" ref="usrDao4Oracle"/>
可以采用set来注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
*/
}
第二种方式:使用注解的方式:
在applicationContext.xml中配置如下内容
<!-- 注解式的配置 -->
<context:annotation-config/>
<!-- 自动扫描与装配bean文件夹dao,service等 -->
<context:component-scan base-package="base,dao,domain,service,service.impl,util,view.action"></context:component-scan>
在代码中:表示service层和dao层间的依赖关系,使用@Resource注解 注入dao层
@Service:在Service层中使用
@Transactional:表示事物管理(不详细做介绍)
@Service
@Transactional
public class RolerServiceImpl implements RoleService {
@Resource
RoleDao roleDao;
// 此处省略若干逻辑代码
}
常见的注解还有:
实例化的注解列表:
@Compoent :应用于普通的类中
@Service:在servie层中使用
@Controller:标记controller层
@Reposistory:在dao层中使用
@Resource:根据设置的明朝名称来进行注入
注入的注解的标签:
@Autowired:自动注入的方式进行注入,默认根据类的名称来进行装配
@Resource(name="")没有name时3和autowired一样但是他可以根据名称进行装配
装配标签:在xml里面的
等等~
小结:还在学习中,请多指教,如果对你有用请点个赞吧~
上一篇: 什么是控制反转(IoC)?
下一篇: 关于maya中的sets集
推荐阅读
-
spring cloud Eureka 配置信息
-
Mybaits 源码解析 (十)----- 全网最详细,没有之一:Spring-Mybatis框架使用与源码解析
-
手把手教你定制标准Spring Boot starter,真的很清晰
-
Spring在代码中获取bean的几种方式详解
-
spring boot 枚举使用的坑整理
-
浅谈Spring Security 对于静态资源的拦截与放行
-
九、Spring之BeanFactory源码分析(一)
-
02Spring基于xml的IOC配置--实例化Bean的三种方式
-
Spring源码分析之IoC容器初始化
-
Spring Boot Security 入门—内存用户验证