Spring学习笔记——Spring依赖注入原理分析
我们知道Spring的依赖注入有四种方式,各自是get/set方法注入、构造器注入、静态工厂方法注入、实例工厂方法注入
以下我们先分析下这几种注入方式
1、get/set方法注入
public class SpringAction {
//注入对象springDao
private SpringDao springDao;
//一定要写被注入对象的set方法
public void setSpringDao(SpringDao springDao) {
this.springDao = springDao;
}
public void ok(){
springDao.ok();
}
}
配置文件例如以下:
<!--配置bean,配置后该类由spring管理-->
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
<!--(1)依赖注入,配置当前类中相应的属性-->
<property name="springDao" ref="springDao"></property>
</bean>
<bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
2、构造器注入
public class SpringAction {
//注入对象springDao
private SpringDao springDao;
private User user;
public SpringAction(SpringDao springDao,User user){
this.springDao = springDao;
this.user = user;
System.out.println("构造方法调用springDao和user");
}
public void save(){
springDao.save(user);
}
}
在XML文件里相同不用的形式,而是使用标签,ref属性相同指向其他标签的name属性:
<!--配置bean,配置后该类由spring管理-->
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
<!--(2)创建构造器注入,假设主类有带參的构造方法则需加入此配置-->
<constructor-arg ref="springDao"></constructor-arg>
<constructor-arg ref="user"></constructor-arg>
</bean>
<bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
<bean name="user" class="com.bless.springdemo.vo.User"></bean>
在XML文件里相同不用的形式,而是使用标签。ref属性相同指向其他标签的name属性:
解决构造方法參数的不确定性。你可能会遇到构造方法传入的两參数都是同类型的,为了分清哪个该赋相应值,则须要进行一些小处理:
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
<constructor-arg index="0" ref="springDao"></constructor-arg>
<constructor-arg index="1" ref="user"></constructor-arg>
</bean>
还有一种是设置參数类型:
<constructor-arg type="java.lang.String" ref=""/>
3、静态工厂方法注入
通过调用静态工厂方法来获取自己须要的对象,为了让Spring管理全部对象,我们不能直接通过类名加方法来获取对象,那样就脱离了Spring的管理,而是通过Spring注入的形式来获取
package com.bless.springdemo.factory;
import com.bless.springdemo.dao.FactoryDao;
import com.bless.springdemo.dao.impl.FactoryDaoImpl;
import com.bless.springdemo.dao.impl.StaticFacotryDaoImpl;
public class DaoFactory {
//静态工厂
public static final FactoryDao getStaticFactoryDaoImpl(){
return new StaticFacotryDaoImpl();
}
}
相同看关键类,这里我须要注入一个FactoryDao对象,这里看起来跟第一种注入一模一样。可是看随后的xml会发现有非常大区别:
public class SpringAction {
//注入对象
private FactoryDao staticFactoryDao;
public void staticFactoryOk(){
staticFactoryDao.saveFactory();
}
//注入对象的set方法
public void setStaticFactoryDao(FactoryDao staticFactoryDao) {
this.staticFactoryDao = staticFactoryDao;
}
}
配置文件例如以下:
<!--配置bean,配置后该类由spring管理-->
<bean name="springAction" class="com.bless.springdemo.action.SpringAction" >
<!--(3)使用静态工厂的方法注入对象,相应以下的配置文件(3)-->
<property name="staticFactoryDao" ref="staticFactoryDao"></property>
</property>
</bean>
<!--(3)此处获取对象的方式是从工厂类中获取静态方法-->
<bean name="staticFactoryDao" class="com.bless.springdemo.factory.DaoFactory" factory-method="getStaticFactoryDaoImpl"></bean>
4、实例工厂方法注入
实例工厂的意思是获取对象实例的方法不是静态的,所以你须要首先new工厂类。再调用普通的实例方法:
public class DaoFactory {
//实例工厂
public FactoryDao getFactoryDaoImpl(){
return new FactoryDaoImpl();
}
}
public class SpringAction {
//注入对象
private FactoryDao factoryDao;
public void factoryOk(){
factoryDao.saveFactory();
}
public void setFactoryDao(FactoryDao factoryDao) {
this.factoryDao = factoryDao;
}
}
<!--配置bean,配置后该类由spring管理-->
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
<!--(4)使用实例工厂的方法注入对象,相应以下的配置文件(4)-->
<property name="factoryDao" ref="factoryDao"></property>
</bean>
<!--(4)此处获取对象的方式是从工厂类中获取实例方法-->
<bean name="daoFactory" class="com.bless.springdemo.factory.DaoFactory"></bean>
<bean name="factoryDao" factory-bean="daoFactory" factory-method="getFactoryDaoImpl"></bean>
对于第1、2种我们用的比較多,对后两种可能比較陌生。
以下我们来分析下Spring是怎样完毕依赖注入的。假设我们去看Spring的源代码可能涉及的类和接口相当多,不易掌握。在此我用自己的代码和方式来帮助我们Spring依赖注入的过程。
当我们启动Spring容器的时候他会运行以下几个过程:
1、载入Xml配置文件(readXML(String filename))在Spring这个由ApplicationContext类完毕
这一步会解析Xml属性。把bean的属性存放到BeanDefinition类中
代码例如以下:
/**
* 读取xml配置文件
* @param filename
*/
private void readXML(String filename) {
SAXReader saxReader = new SAXReader();
Document document=null;
try{
URL xmlpath = this.getClass().getClassLoader().getResource(filename);
document = saxReader.read(xmlpath);
Map<String,String> nsMap = new HashMap<String,String>();
nsMap.put("ns","http://www.springframework.org/schema/beans");//加入命名空间
XPath xsub = document.createXPath("//ns:beans/ns:bean");//创建beans/bean查询路径
xsub.setNamespaceURIs(nsMap);//设置命名空间
List<Element> beans = xsub.selectNodes(document);//获取文档下全部bean节点
for(Element element: beans){
String id = element.attributeValue("id");//获取id属性值
String clazz = element.attributeValue("class"); //获取class属性值
BeanDefinition beanDefine = new BeanDefinition(id, clazz);
XPath propertysub = element.createXPath("ns:property");
propertysub.setNamespaceURIs(nsMap);//设置命名空间
List<Element> propertys = propertysub.selectNodes(element);
for(Element property : propertys){
String propertyName = property.attributeValue("name");
String propertyref = property.attributeValue("ref");
PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName, propertyref);
beanDefine.getPropertys().add(propertyDefinition);
}
beanDefines.add(beanDefine);
}
}catch(Exception e){
e.printStackTrace();
}
}
2、Bean的实例化
在配置文件以bean的id为key。BeanDefinition为value放到Map中
/**
* 完毕bean的实例化
*/
private void instanceBeans() {
for(BeanDefinition beanDefinition : beanDefines){
try {
if(beanDefinition.getClassName()!=null && !"".equals(beanDefinition.getClassName().trim()))
sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、为Bean的输入注入值。完毕依赖注入
/**
* 为bean对象的属性注入值
*/
private void injectObject() {
for(BeanDefinition beanDefinition : beanDefines){
Object bean = sigletons.get(beanDefinition.getId());
if(bean!=null){
try {
PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
for(PropertyDefinition propertyDefinition : beanDefinition.getPropertys()){
for(PropertyDescriptor properdesc : ps){
if(propertyDefinition.getName().equals(properdesc.getName())){
Method setter = properdesc.getWriteMethod();//获取属性的setter方法 ,private
if(setter!=null){
Object value = sigletons.get(propertyDefinition.getRef());
setter.setAccessible(true);
setter.invoke(bean, value);//把引用对象注入到属性
}
break;
}
}
}
} catch (Exception e) {
}
}
}
}
事实上Spring依赖注入的过程就是这么简单,再就是各种细节了。比方懒载入、单例等的额外处理了。
Spring学习笔记——Spring依赖注入原理分析的更多相关文章
- Spring学习笔记1—依赖注入(构造器注入、set注入和注解注入)
什么是依赖注入 在以前的java开发中,某个类中需要依赖其它类的方法时,通常是new一个依赖类再调用类实例的方法,这种方法耦合度太高并且不容易测试,spring提出了依赖注入的思想,即依赖类不由程序员 ...
- Spring依赖注入原理分析
在分析原理之前我们先回顾下依赖注入的概念: 我们常提起的依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念.具体含义是:当某个角色( ...
- Spring学习笔记之依赖的注解(2)
Spring学习笔记之依赖的注解(2) 1.0 注解,不能单独存在,是Java中的一种类型 1.1 写注解 1.2 注解反射 2.0 spring的注解 spring的 @Controller@Com ...
- SpringMVC:学习笔记(11)——依赖注入与@Autowired
SpringMVC:学习笔记(11)——依赖注入与@Autowired 使用@Autowired 从Spring2.5开始,它引入了一种全新的依赖注入方式,即通过@Autowired注解.这个注解允许 ...
- spring 控制反转与依赖注入原理-学习笔记
在Spring中有两个非常重要的概念,控制反转和依赖注入:控制反转将依赖对象的创建和管理交由Spring容器,而依赖注入则是在控制反转的基础上将Spring容器管理的依赖对象注入到应用之中: 所谓依赖 ...
- [Spring学习笔记 4 ] AOP 概念原理以及java动态代理
一.Spring IoC容器补充(1) Spring IoC容器,DI(依赖注入): 注入的方式:设值方法注入setter(属性注入)/构造子注入(构造函数传入依赖的对象)/字段注入Field(注解) ...
- Spring学习笔记--spring+mybatis集成
前言: 技术的发展, 真的是日新月异. 作为javaer, 都不约而同地抛弃裸写jdbc代码, 而用各种持久化框架. 从hibernate, Spring的JDBCTemplate, 到ibatis, ...
- Spring学习笔记—Spring之旅
1.Spring简介 Spring是一个开源框架,最早由Rod Johnson创建,并在<Expert One-on-One:J2EE Design and Development> ...
- Spring学习笔记--Spring配置文件和依赖注入
Spring配置文件 1.alias:设置别名,为bean设置别名,并且可以设置多个别名; <!-- 设置别名 --> <alias name="user" al ...
随机推荐
- [k8s]dashboard1.8.1搭建( heapster1.5+influxdb+grafana)
dashboard最终效果 多了执行sh的窗口 heapster+influxdb+grafana搭建 整个架构是 dashboard去检测 hepster service服务, heapster通过 ...
- 使用Xcode 5创建Cocoa Touch Static Library(静态库)
转自:http://blog.csdn.net/jymn_chen/article/details/21036035 首先科普一下静态库的相关知识: 程序编译一般需经预处理.编译.汇编和链接几个步骤. ...
- jvm 性能调优 经验总结---转
最近因项目存在内存泄漏,故进行大规模的JVM性能调优 , 现把经验做一记录. 一.JVM内存模型及垃圾收集算法 1.根据Java虚拟机规范,JVM将内存划分为: New(年轻代) Tenured(年老 ...
- sass & compass 实战录
一.sass 是什么 Css的一种预处理器 是基于css进行语法扩展而成 主要目的是为了提高开发效率,弥补css语法不足的缺陷 同样流行的预处理器还有:less.stylus 二.SASS的基本语法 ...
- oracle 实现插入自增列(类似SqlServer Identity)
oracle不像sql server 有关键字identity直接可插入数据时自增 ,Oracle是不能用Identity,可以使用Sequence Create Table Tempinfo( id ...
- 支持移动触摸设备的简洁js幻灯片插件
lory是一款支持移动触摸设备的简洁的js幻灯片插件.该幻灯片插件可以通过纯js调用,也可以将该幻灯片插件作为jQuery插件来使用.该幻灯片的过渡动画具有硬件加速功能,并且可以定制是否使用easin ...
- 一款jquery实现的整屏切换特效
今天要为大家带来一款由jquery实现的整屏切换特效,在右侧有圆型小标,每点一个切换一屏.当然,你也可以滚动鼠标来切换页面.效果非常好.我们看下效果吧 在线预览 源码下载 html代码: < ...
- 风雪之隅(Laruence PHP开发组成员, Zend兼职顾问, Yaf, Yar, Yac, Opcache等项目作者、维护者.)
http://www.laruence.com/?from=inf&wvr=5&loc=infblog
- 跟我学TCP/IP系列
最近在微信公众号“java与Android开发专栏”,看到系列文章“跟我学TCP/IP系列”,共7章,文章很赞. 系列文章在CSDN上也有分发,下列出地址以备以后查看(版权问题不转载内容). http ...
- Android自己定义控件--圆形进度条(中间有图diao)
智能家居越来越流行,在智能家居中我们常要表现一些数据的百分比 圆形度条中间加个图是一种很流行的自己定义View 1.第一步 你首先须要对类进行继承View public class CirclePro ...