一、一个简单的示例

1、引入依赖和配置

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.fonxian</groupId>
<artifactId>learnspring</artifactId>
<version>1.0-SNAPSHOT</version> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.6.RELEASE</version>
</dependency>
</dependencies> </project>

resources/META-INF下创建applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="hello" class="com.fonxian.test.HelloWorld">
<property name="name" value="Hello,Spring!"></property>
</bean> </beans>

2、包下面创建HelloWorld


public class HelloWorld { private String name; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("META-INF/applicationContext.xml");
HelloWorld t=(HelloWorld) ctx.getBean("hello");
System.out.println(t.getName());
} }

3、运行后得到结果

二、概念介绍

两个重要概念:AOP和IOC

IOC是控制反转,AOP是面向切面编程

先来看看IOC。

Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

控制指的是IOC容器控制对象,控制外部资源的获取

反转指的是原先编程人员主动创建对象,现在交给容器创建。

这样做有什么优点?

解耦

传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器

IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。

IoC和DI有什么区别?

是同一个概念的不同角度描述.

依赖指的是IoC容器来提供对象需要的外部资源

注入指IoC容器注入应用程序某个对象,应用程序依赖的对象

3种注入方式

构造注入

public classA(IinterfaceA a,IinterfaceB b){
this.a=a;
this.b=b;
}

setter 方法注入


public class classB(){
private IinterfaceA a;
private IinterfaceB b;
public IinterfaceA getIinterfaceA(){
return a;
}
public void setIinterfaceA(IinterfaceA a){
this.a=a;
}
public IinterfaceB getIinterfaceB(){
return b;
}
public void setIinterfaceB(IinterfaceB b){
this.b=b;
}
}

接口注入

interface UserInject{
void injectUser(User user);//这里必须 是被注入对象依赖的对象
} class Person implements UserInject{
private User user;
public Person(){}
@Override
public void injectUser(User user)
{
this.user = user;//实现注入方法,外部通过此方法给此对象注入User对象
}
}

3种注入方式的比较

接口注入侵入性强,另外两种侵入性弱。

三、源码分析


ApplicationContext ctx=new ClassPathXmlApplicationContext("META-INF/applicationContext.xml");
//获取bean的实例
HelloWorld t=(HelloWorld) ctx.getBean("hello");

通过Resource对象加载配置文件

解析配置文件,得到bean

解析bean,id作为bean的名字,class用于反射得到bean的实例(Class.forName(className));

调用getBean的时候,从容器中返回对象实例。

IOC核心内容是beanFactory与ApplicationContext

茶底世界

读万卷书,行万里路

spring之旅第二篇-spring IOC概念及原理分析

一、IOC概念

上一篇已经了解了spring的相关概念,并且创建了一个spring项目。spring中有最重要的两个概念:IOC和AOP,我们先从IOC入手。

IOC全称Inversion of Control,中文通常翻译为“控制反转”,这其实不是一种技术,而是一种思想。

简单理解就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。

这里分享Iteye的开涛对Ioc的精彩讲解

地址:https://jinnianshilongnian.iteye.com/blog/1413846

IoC是什么

  Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:

  ●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。

  ●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

 用图例说明一下,传统程序设计如图1-1,都是主动去创建相关对象然后再组合起来:

图1-1 传统应用程序示意图

当有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象了,如图2-2所示:

图1-2有IoC/DI容器后程序结构示意图

IoC能做什么

IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是 松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

  其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。

  IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。

IoC和DI

DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

  理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:

  ●谁依赖于谁:当然是应用程序依赖于IoC容器;

  ●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源

  ●谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;

  ●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

  IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“**依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。

相信通过上面的文章,对IOC的理解会更深。下面讲讲三种依赖注入的方式

构造方法注入

顾名思义,构造方法注入,就是被注入对象可以通过在其构造方法中声明依赖对象的参数列表, 让外部(通常是IoC容器)知道它需要哪些依赖对象

public classA(IinterfaceA a,IinterfaceB b){

this.a=a;

this.b=b;

}

构造方法注入方式比较直观,对象被构造完成后,即进入就绪状态,可以马上使用。

setter 方法注入

对于JavaBean对象来说,通常会通过setXXX()和getXXX()方法来访问对应属性。这些setXXX()方法统称为setter方法,getXXX()当然就称为getter方法。

按 Ctrl+C 复制代码

public class classB(){

private IinterfaceA a;

private IinterfaceB b;

public IinterfaceA getIinterfaceA(){

return a;

}

public void setIinterfaceA(IinterfaceA a){

this.a=a;

}

public IinterfaceB getIinterfaceB(){

return b;

}

public void setIinterfaceB(IinterfaceB b){

this.b=b;

}

}

按 Ctrl+C 复制代码

接口注入  

相对于前两种注入方式来说,接口注入没有那么简单明了。被注入对象如果想要IoC Service Provider为其注入依赖对象,就必须实现某个接口。这个接口提供一个方法,用来为其注入依赖对象。IoC Service Provider最终通过这些接口来了解应该为被注入对象注入什么依赖对象。

创建Person (被注入对象)要实现的接口

interface UserInject{

void injectUser(User user);//这里必须 是被注入对象依赖的对象

}

Person 对象实现接口

复制代码

class Person implements UserInject{

private User user; public Person(){}

@Override

public void injectUser(User user)

{

this.user = user;//实现注入方法,外部通过此方法给此对象注入User对象

}

}

复制代码

外部调injectUser方法为Persion对象注入User对象,此即接口注入

三种注入方式的比较

接口注入。从注入方式的使用上来说,接口注入是现在不甚提倡的一种方式,基本处于“退役状态”。因为它强制被注入对象实现不必要的接口,带有侵入性。而构造方法注入和setter方法注入则不需要如此。

构造方法注入。这种注入方式的优点就是,对象在构造完成之后,即已进入就绪状态,可以 9马上使用。缺点就是,当依赖对象比较多的时候,构造方法的参数列表会比较长。而通过反射构造对象的时候,对相同类型的参数的处理会比较困难,维护和使用上也比较麻烦。而且在Java中,构造方法无法被继承,无法设置默认值。对于非必须的依赖处理,可能需要引入多个构造方法,而参数数量的变动可能造成维护上的不便。

setter方法注入。因为方法可以命名,所以setter方法注入在描述性上要比构造方法注入好一些。 另外,setter方法可以被继承,允许设置默认值,而且有良好的IDE支持。缺点当然就是对象无法在构造完成后马上进入就绪状态。

综上所述,构造方法注入和setter方法注入因为其侵入性较弱,且易于理解和使用,所以是现在使用最多的注入方式;而接口注入因为侵入性较强,近年来已经不流行了。

二、源码分析

在学习spring的具体配置之前,先了解下源码的基本结构。上一篇的测试代码

ApplicationContext ctx=new ClassPathXmlApplicationContext("META-INF/applicationContext.xml");

//获取bean的实例

HelloWorld t=(HelloWorld) ctx.getBean("hello");

我们大致分析下过程:

通过Resource对象加载配置文件

解析配置文件,得到bean

解析bean,id作为bean的名字,class用于反射得到bean的实例(Class.forName(className));

调用getBean的时候,从容器中返回对象实例。

当然这只是简单的理解,IOC核心内容是beanFactory与ApplicationContext

BeanFactory

BeanFactory 是 Spring 的“心脏”。它就是 Spring IoC 容器的真面目。Spring 使用 BeanFactory 来实例化、配置和管理 Bean。

BeanFactory


public interface BeanFactory { //根据bean的名字,获取在IOC容器中得到bean实例
Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; boolean containsBean(String name); boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name); }

xml

@Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory { private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
} public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
} }

参考文档

Spring:源码解读Spring IOC原理

Spring框架浅析的更多相关文章

  1. 【Spring】浅析Spring框架的搭建

    c目录结构: // contents structure [-] Spring是什么 搭建Spring框架 简单Demo 1,建立User类 2,建立Test类 3,建立ApplicationCont ...

  2. 【Spring】Spring之浅析Spring框架的搭建

    Spring是什么 Spring是一个开源的容器框架,用于配置bean并且维护bean之间关系的.其主要的思想就是IOC(Inversion Of Control,控制反转)或者称作DI(Depend ...

  3. 浅析Spring框架之一(Spring简介)

    免责声明 本文为鄙人搜集网络资源并结合自己所思所得整理而成,如有侵权,敬请谅解. 何为spring框架 Spring是一个开源的轻量级控制反转(IoC)和面向切面(AOP)的容器框架. ◆目的:解决企 ...

  4. Spring框架入门浅析

    一.Spring Bean的配置 在需要被Spring框架创建对象的实体类的类声明前面加注解:```@component```.这样在Spring扫描的时候,看到该注解就会在容器中创建该实体类的对象. ...

  5. Spring框架概述

    Spring是最流行的Java企业级应用开发框架,全球数以百万的开发者在使用Spring框架创建高性能.易测试.可重用的代码. Spring框架的核心特性可以应用于任何Java应用,但扩展的JavaE ...

  6. 初识Spring框架实现IOC和DI(依赖注入)

    学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的, IoC是 ...

  7. Spring 框架的架包分析、功能作用、优点,及jar架包简介

    Spring 框架的架包详解    Spring的作用     Spring的优势  由于刚搭建完一个MVC框架,决定分享一下我搭建过程中学习到的一些东西.我觉得不管你是个初级程序员还是高级程序员抑或 ...

  8. 最新 Eclipse IDE下的Spring框架配置及简单实例

    前段时间开始着手学习Spring框架,又是买书又是看视频找教程的,可是鲜有介绍如何配置Spring+Eclipse的方法,现在将我的成功经验分享给大家. 本文的一些源代码来源于码农教程:http:// ...

  9. spring框架学习(三)

    一.Spring自动组件扫描 Spring 提供组件扫描(component scanning)功能.它能从指定的classpath里自动扫描.侦测和实例化具有特定注解的组件. 基本的注解是@Comp ...

随机推荐

  1. 获取jwt(json web token)中存储的用户信息

    一个JWT实际上就是一个字符串,它由三部分组成,头部(header).载荷(Payload)与签名. Payload payload中可以保存用户的信息. var claims = new Claim ...

  2. 读取Excel文件存储在实体类中

    1.Maven文件 <!--读取Excel的架包--> <dependency> <groupId>org.apache.poi</groupId> & ...

  3. 圆形进度条css3样式

    <view class="con"> <view class="percent-circle percent-circle-left"> ...

  4. 31 ArcGIS中后缀一览表(持续更新中……)

  5. Objective-C 优秀文章分享

    1.  Objective-C Runtime 2.KVO + Block 3.Method Swizzling 和 AOP 实践

  6. zepto与jquery冲突的解决

    一般是不会把zepto和jquery一起来用的.但有时候要引入一些插件,可能就会遇到这样的问题. jquery noConflict() jquery有一个方法叫noConflict() ,可以把jq ...

  7. [Swift]LeetCode649. Dota2 参议院 | Dota2 Senate

    In the world of Dota2, there are two parties: the Radiantand the Dire. The Dota2 senate consists of ...

  8. 阿里云rds数据库迁移实战(多数据源)

    由于某几个业务表数据量太大,数据由业务写,数据部门读. 写压力不大,读却很容易导致长时间等待问题(读由单独系统进行读),导致连接被占用,从而容易并发稍稍增长导致全库卡死! 于是,就拆库呗. 业务系统拆 ...

  9. Javaweb编程中的乱码问题

    程序中的乱码问题,主要出现在我们处理中文数据的过程中出现.从浏览器向服务器请求数据,服务器返回的数据在浏览器中显示为乱码.或者是服务器中的java文件用到中文,也有可能会出现乱码.数据库在处理数据的时 ...

  10. Python内置函数(36)——iter

    英文文档: iter(object[, sentinel]) Return an iterator object. The first argument is interpreted very dif ...