Spring得全面讲解-IOC

结合面试经常问得有关spring得问题。

来进行深度剖析spring

什么是spring?

spring是一个开源框架,是为了解决企业应用开发得复杂性而创建得。

从简单性、可测试性和松耦合的角度来说,任何Java应用都可以从Spring中受益。

说到spring,就不得不说IOC和AOP

IOC:

从字面上理解就是控制反转,也就是将管理对象得权力交给spring。

其实可以将IOC看成一个map,其中beanname是key,bean实例对象是value。(可以使用这种方法实现一个简单的ioc容器)

//还可以讲讲IOC容器

//讲讲IOC的优点

//讲讲几种注入的方式

先从IOC容器开始讲解,spring中IOC容器实现:beanFactory和applicationContext

BeanFactory是容器基础设计,ApplicationContext增加一些扩展功能,应该说后者是前者的高级形态。

beanFactory:可以说说整个beanFactory的生命流程

http://www.tianxiaobo.com/2018/01/18/%E8%87%AA%E5%B7%B1%E5%8A%A8%E6%89%8B%E5%AE%9E%E7%8E%B0%E7%9A%84-Spring-IOC-%E5%92%8C-AOP-%E4%B8%8B%E7%AF%87/

1.beanFactory加载bean的配置文件,将读取的到的bean装成BeanDefinition对象

2.然后再将封装好的BeanDefinition对象注册到容器中

 

 

然后再根据beanfactory的生命流程继续往下说

applicationContext

spring依赖注入得三个方式

构造器注入
Setter方法注入
接口注入

//注解注入

spring中bean的作用域:

singleton:这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由bean factory自身来维护。
prototype:原形范围与单例范围相反,为每一个bean请求提供一个实例。
request:在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
Session:与请求范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
global-session:global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。
全局作用域与Servlet中的session作用域效果相同。

bean的生命周期:

定义

初始化

使用

销毁

1.bean容器在配置文件中找到bean的定义

2.创建bean的实例(通过java反射机制)

3.如果涉及到属性值,则使用set方法进行赋值

4.如果实现了beanNameAware接口,(则调用setBeanName()方法),传入beanName

6.如果实现了beanFactoryAware接口,(则调用SetBeanClassLoader())传入ClassLoader对象的实例。

7.如果实现了ApplicationContextAware接口,则传入ApplicationContext对象的实例

8.与上面的类似,如果实现了其他*Aware接口,就调用相应的方法。

---------------------分界线---------------

9.如果有加载和BeanPostProcessor对象相关的则执行postProcessorBeforeInitalization()方法

--------------------分界线------------------

10.如果实现了InitalizingBean接口,则执行他的setproporiteidsAfter()

11.如果bean在配置文件中含有init-method属性,则执行对应的方法

--------------------分界线----------------------

12.如果有加载和BeanPostProcessor对象相关的则执行postProcessorAfterInitalization()方法

---------------------分界线--------------------

13.如果实现了DisposableBean接口,则要执行相应的destory()方法

14.如果bean在配置文件中定义中含有destory-method属性,则执行相应的方法

单例管理的对象:

当scope="singleton",或者为默认情况下,bean会在容器进启动的时候(容器初始化)进行初始化。但是可以使用lazy-init=“true”的方法进行延迟初始化,也就是当第一次请求该bean的时候才会进行初始化

在默认情况下,在spring读取xml文件的时候就会创建对象,在创建对象的时候先调用构造器,然后执行init-method的相应方法。当对象被销毁的时候会调用destory-method()方法

非单例管理的对象:

当scope="prototype"的时候,spring也会延迟初始化 bean,也就是说spring在读取xml文件的时候并不会立刻就创建bean对象,只有在请求该bean的时候才会进行初始化。在第一次请求每一个prototype的bean的时候,spring都会让构造器去创建对象然后调用init-mehod属性指定的方法。

同时对于destory-method对象的方法对于非单例管理的对象是没有用的,也就是说spring只负责创建bean对象的实例给我们,然后就不再管这个对象了。

//

有时候会经常被问到让你手写一个ioc容器

手撕IOC容器:

1.先来个简单的使用map来实现的

//有一个弊端就是:

classA里面有个属性是classB,在bean中写的话必须先写classB的bean,后写classA的bean

public class SimpleIOC {
	private Map<String, Object> beanMap=new HashMap<>();
	
	public SimpleIOC(String location) throws Exception{
		loadBean(location);
	}
	

	public Object getBean(String name) {
		Object bean = beanMap.get(name);
		if (bean==null) {
			throw new IllegalArgumentException("there is no bean with beanName:"+name);
		}
		return bean;
	}
	
    private void loadBean(String location) throws Exception {
    	//加载xml配置文件
		InputStream inputStream=new FileInputStream(location);
		DocumentBuilderFactory  factory=DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder=factory.newDocumentBuilder();
		Document doc=docBuilder.parse(inputStream);
		Element root = doc.getDocumentElement();
		NodeList nodes=root.getChildNodes();
		for (int i = 0; i < nodes.getLength(); i++) {
			Node node = nodes.item(i);
			if (node instanceof Element) {
				Element ele = (Element) node;
				String id = ele.getAttribute("id");
				String className = ele.getAttribute("class");
				//加载beanclass
				Class beanClass = null ;
				beanClass=Class.forName(className);
				//创建bean
				Object bean=beanClass.newInstance();
				// 遍历 <property> 标签
                NodeList propertyNodes = ele.getElementsByTagName("property");
                for (int j = 0; j < propertyNodes.getLength(); j++) {
					Node propertyNode = propertyNodes.item(i);
					if (propertyNode instanceof Element) {
						Element pele = (Element) propertyNode;
						String name  = pele.getAttribute("name");
						String value = pele.getAttribute("value");
						
						 // 利用反射将 bean 相关字段设为可以访问
						Field declareField = bean.getClass().getDeclaredField(name);
						declareField.setAccessible(true);
						//可能是value,也可能是ref
						if (null!=value && value.length() > 0) {
							//将相关字段赋值
							declareField.set(bean,value);
						}else {
							String ref=pele.getAttribute("ref");
							if (ref == null || ref.length() == 0) {
                                throw new IllegalArgumentException("ref config error");
                            }
                            
                            // 将引用填充到相关字段中
							declareField.set(bean, getBean(ref));
						}
						
					}
				}
                //将bean注册到bean容器中
				beanMap.put(id, bean);
						
			}
		}
		
		
	}

}

///测试类
public class SimpleIOCTest {

	public static void main(String[] args) {
		try {
			SimpleIOC ioc = new SimpleIOC("IOC.xml");
			Food food =(Food) ioc.getBean("food");
			
			System.out.println("food的name:"+food.getName());
			System.out.println("food的color:"+food.getApple().getColor());
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

 

spring中bean得创建是典型得工程模式。其中BeanFactory是最顶层得接口,也是Spring IoC 容器的核心接口。但是BeanFactory只是对IOC得基本容器行为做了定义,并不关心bean是如何加载得。他只负责生产和管理bean得一个工厂,

spring中BeanFactory得源码:

public interface BeanFactory {    
     
     //对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,    
     //如果需要得到工厂本身,需要转义           
     String FACTORY_BEAN_PREFIX = "&"; 
        
     //根据bean的名字,获取在IOC容器中得到bean实例    
     Object getBean(String name) throws BeansException;    
   
    //根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。    
     Object getBean(String name, Class requiredType) throws BeansException;    
    
    //提供对bean的检索,看看是否在IOC容器有这个名字的bean    
     boolean containsBean(String name);    
    
    //根据bean名字得到bean实例,并同时判断这个bean是不是单例    
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;    
    
    //得到bean实例的Class类型    
    Class getType(String name) throws NoSuchBeanDefinitionException;    
    
    //得到bean的别名,如果根据别名检索,那么其原名也会被检索出来    
   String[] getAliases(String name);    
    
 }

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值