Spring学习笔记——Spring依赖注入原理分析

本文内容纲要: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依赖注入原理分析

原文链接:https://www.cnblogs.com/mthoutai/p/7278427.html

以上是 Spring学习笔记——Spring依赖注入原理分析 的全部内容, 来源链接: utcz.com/z/362606.html

回到顶部