Spring--IOC

来源:互联网 发布:虚拟机下安装linux 编辑:程序博客网 时间:2024/06/06 00:12

经典讲述IOC的博客:http://blog.csdn.net/qq_22654611/article/details/52606960
1 控制反转(Inversion of Control)简称IOC,IOC的思想是:Spring容器来实现这些相互依赖对象的创建、协调工作。对象只需要关系业务逻辑本身就可以了。由spring来负责控制对象的生命周期和对象间的关系。从这方面来说,对象如何得到他的协作对象的责任被反转了(IOC、DI)。IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。org.springframework.beans及org.springframework.context包 是Spring IoC容器的基础,ApplicationContext 是BeanFactory的扩展,功能得到了进一步增强,比如更易 与Spring AOP集成、资源处理(国际化处理)、事件传递及各种不同应用层的context实现 BeanFactory 是Spring IoC容器的实际代表者,IoC容器负责容纳此前所描述的bean,并对bean进行管理。BeanFactory是IoC容器的核心接口。 它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。Spring为我们提供了许多易用的BeanFactory实现, XmlBeanFactory就是最常用的一个。
2 XML的配置元数据的基本结构:

<bean name="hello" class="cn.sxt.bean.Hello">        <property name="name" value="张三"></property>    </bean>

Spring IoC容器的实例化:

public class Hello {    private String name;    public void setName(String name) {        this.name = name;    }    public void show(){        System.out.println("hello,"+name);    }}//解析beans.xml文件 生成管理相应的bean对象        ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");         Hello hello=(Hello)context.getBean("hello");        hello.show();

3.2 实例化bean
3.2.1 构造器实例化Bean:

beans.xml:<bean id="u" class="cn.sxt.vo.User"/>ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");        User user=(User)ac.getBean("u");        System.out.println(user);

需要注意的是一定要存在一个默认的构造器。

3.2.2 使用静态工厂方法实例化

<!-- factory-method指定创建对象的静态方法 -->    <bean id="u" class="cn.sxt.vo.User" factory-method="newinstance"/>测试:ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");        User user=(User)ac.getBean("u");        System.out.println(user);

3.2.3 使用实例化方法实例

<bean id="userFactory" class="cn.sxt.factory.UserDynamicFactory"/>    <!-- factory-bean设置创建对象的工厂 factory-method指定创建对象的方法-->    <bean id="user" factory-bean="userFactory" factory-method="newinstance"/>

3.2.4 使用容器:

Resource res=new FileSystemResource("src/beans.xml");BeanFactory bean=new XmlBeanFactory(res);User user=(User)bean.getBean("user");System.out.println(user.getName());<bean id="u" class="cn.sxt.vo.User" factory-method="newinstance"/>

4 注入依赖
依赖注入(DI)背后的基本原理是对象之间的依赖关系(即一起工作的其它对象)只会通过以下几种方式来实现:构造器的参数、工厂方法的参数,或给由构造函数或者工厂方法创建的对象设置属性。因此,容器的工作就是创建bean时注入那些依赖关系。
4.1 构造器注入
基于构造器的DI通过调用带参数的构造器来实现,每个参数代表着一个依赖。
4.1.1 构造器参数解析
构造器参数解析根据参数类型进行匹配,如果bean的构造器参数类型定义非常明确,那么在bean被实例化的时候,bean定义中构造器参数的定义顺序就是这些参数的顺序,依次进行匹配。

public class Foo {    public Foo(Bar bar, Baz baz) {        // ...    }}<bean name="foo" class="x.y.Foo">        <constructor-arg>            <bean class="x.y.Bar"/>        </constructor-arg>        <constructor-arg>            <bean class="x.y.Baz"/>        </constructor-arg>    </bean>

4.1.2 构造器参数类型匹配

<bean id="user" class="cn.sxt.vo.User">        <!-- 通过参数类型进行匹配 -->        <constructor-arg type="java.lang.String" value="tang"/>    </bean>

4.1.3 构造参数索引

<bean id="user" class="cn.sxt.vo.User">        <!-- 根据参数的位置设置为索引来对指定位置的数进行注入 从0开始-->        <constructor-arg index="0" value="tang"/>    </bean>

4.2 Setter注入
4.2.1 通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法,即可实现基于setter的DI。

<bean id="mysqlDao" class="cn.sxt.dao.impl.UserDaoMySqlImpl"/>    <bean id="oralceDao" class="cn.sxt.dao.impl.UserDaoOracleImpl"/>    <bean id="service" class="cn.sxt.service.impl.UserServiceImpl">        <!--        ref引用对象,通过Id引用对象注入 -->        <!-- 随着此处位置的引用的不同ID,而UserDaoMySqlImplUserDaoO        racleImpl均实现UserDao接口,将注入不同的对象 -->        <property name="userDao" ref="oralceDao"></property>    </bean>public class UserDaoMySqlImpl implements UserDao{    @Override    public void getUser() {        System.out.println("mysql获取用户数据");      }}public class UserDaoOracleImpl implements UserDao{    @Override    public void getUser() {        // TODO Auto-generated method stub        System.out.println("orac获取用户数据");    }}public interface UserService {    public void getUser();}public class UserServiceImpl implements UserService{    private UserDao userDao=null;    public void setUserDao(UserDao userDao) {        this.userDao = userDao;    }    @Override    public void getUser() {        userDao.getUser();    }}

4.2.2 注入到构造器

<bean id="service" class="cn.sxt.service.impl.UserServiceImpl">        <constructor-arg>            <ref bean="oralceDao"/>        </constructor-arg>    </bean>

4.2.3 采用static工厂方法返回对象实例:

<!-- 在BeanFactoryCustom中定义一个bean静态方法, -->    <bean id="service" class="cn.sxt.service.impl.BeanFactoryCustom" factory-method="createInstance">        <!-- 注入到bean静态方法中 -->        <constructor-arg ref="oralceDao"/>    </bean>public class UserServiceImpl implements UserService{    private UserDao userDao=null;    public UserServiceImpl(UserDao userDao) {        this.userDao = userDao;    }    public void setUserDao(UserDao userDao) {        this.userDao = userDao;    }    @Override    public void getUser() {        userDao.getUser();    }}public static UserServiceImpl createInstance(UserDao userDao){        //根据参数创建对象        return new UserServiceImpl(userDao);    }

5 集合:
需要注意的是,数据注入时,Spring的底层会强制发生强制转换。没有value值时,将设置为“ ”值,即空字符串。

<bean id="addr" class="cn.sxt.vo.Address">        <property name="address" value="北京西三旗"></property>    </bean>    <bean id="student" class="cn.sxt.vo.Student"><!--        注入属性 -->        <property name="name" value="张三丰"></property><!--        注入对象 -->        <property name="addr" ref="addr"/><!--        注入数组 -->        <property name="books">            <array>                <value>傲慢与偏见</value>                <value>仲夏之梦</value>                <value>雾都孤儿</value>            </array>        </property>        <!-- 注入List集合 -->        <property name="hobbies">            <list>                <value>羽毛球</value>                <value>乒乓球</value>                <value>玻璃球</value>            </list>        </property>        <!-- 注入Map集合 -->        <property name="cards">            <map>                <entry key="中国银行" value="1212121"></entry>                <entry key="建设银行" value="1223232"></entry>                <entry key="交通银行" value="1323232"></entry>            </map>        </property>        <!-- 注入Set集合 -->        <property name="games">            <set>                <value>lol</value>                <value>dota</value>                <value>cs</value>                <value>dnf</value>            </set>        </property>        <!-- 注入字符 -->        <property name="wife">            <null/>        </property>        <!-- 注入配置信息 -->        <property name="info">            <props>                <prop key="学号">20150512601</prop>                <prop key="sex"></prop>                <prop key="name">小乔</prop>            </props>        </property>    </bean>

还可以使用p名称空间配置属性如下:

    <bean name="john-classic" class="com.example.Person">        <property name="name" value="John Doe"/>        <property name="spouse" ref="jane"/>    </bean>    <bean name="john-modern"         class="com.example.Person"        p:name="John Doe"        p:spouse-ref="jane"/>    <bean name="jane" class="com.example.Person">        <property name="name" value="Jane Doe"/>    </bean></beans>

需要说明的是集合支持合并,子集合将会覆盖父集合中的数据。List集合由于是有序存在的。父集合中的数据将在子集合元素之前。不同集合类型之间是不能合并的。
如:

<beans><bean id="parent" abstract="true" class="example.ComplexObject">    <property name="adminEmails">        <props>            <prop key="administrator">administrator@example.com</prop>            <prop key="support">support@example.com</prop>        </props>    </property></bean><bean id="child" parent="parent">    <property name="adminEmails">        <!-- the merge is specified on the *child* collection definition -->        <props merge="true">            <prop key="sales">sales@example.com</prop>            <prop key="support">support@example.co.uk</prop>        </props>    </property></bean><beans>

6 depends-on属性
depends-on属性可以用于当前bean初始化之前显式地强制一个或多个bean被初始化。防止出现依赖的对象没有生成。

7 方法注入:
7.1 在大部分情况下,容器中的bean都是singleton类型的。如果一个singleton bean要引用另外一个singleton bean,或者一个非singleton bean要引用另外一个非singleton bean时,通常情况下将一个bean定义为另一个bean的property值就可以了。对于不同周期的Bean,当一个singleton类型的Bean A中的方法需要使用另一个全新的非singleton类型的Bean B时,那么只能通过实现BeanFactoryAware接口,在需要的地方使用getBean(” “)请求一个Bean实例。
如下:

public class CommandManager implements BeanFactoryAware {    private BeanFactory beanFactory;    public Object process() {        System.out.println("process");        //获取一个实例        Command command = createCommand();        //执行Command中的方法        return command.execute();    }    /**     * 获取一个command实例     * @return Command对象     */    protected Command createCommand() {        return (Command) this.beanFactory.getBean("command");    }    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {        System.out.println("setBeanFactory");        this.beanFactory = beanFactory;    }}

其中setBeanFactory方法,在Bean的属性初始化后调用。
执行结果:
这里写图片描述
参考:http://blog.csdn.net/heyutao007/article/details/5981555
7.2 通过lookup方式:
定义一个抽象类,包含一个抽象方法,访问级别必须是public或protected,保证能被子类重载,可以是抽象方法,必须有返回值,必须是无参数方法,用于创建需要注入的方法的Bean。

public abstract class HelloImpl5 implements HelloApi {      private Printer printer;      //放回一个全新的对象。    public abstract Printer createPrototypePrinter();  }  <bean id="prototypePrinter"  class="cn.javass.spring.chapter3.bean.Printer" scope="prototype"/>  <bean id="singletonPrinter"  class="cn.javass.spring.chapter3.bean.Printer" scope="singleton"/>  <bean id="helloApi1" class="cn.javass.spring.chapter3.HelloImpl5" scope="singleton">  <property name="printer" ref="prototypePrinter"/>  //生成一个bean对应的对象作为createPrototypePrinter的返回值。<lookup-method name="createPrototypePrinter" bean="prototypePrinter"/>  </bean>       

7.3 方法替换
1 定义一个类实现MethodReplacer接口,实现reimplement方法,参数obj为被替换方法的对象,method为被替换方法,args为方法参数;
2 配置
,使用< replaced-method >标签来指定要进行替换方法,属性name指定替换的方法名字,replacer指定该方法的重新实现者,子标签< arg-type >用来指定原来方法参数的类型,必须指定否则找不到原方法,如下将print替换:

<bean id="replacer" class="cn.javass.spring.chapter3.bean.PrinterReplacer"/>  <bean id="printer" class="cn.javass.spring.chapter3.bean.Printer">  <replaced-method name="print" replacer="replacer">          <arg-type>java.lang.String</arg-type>      </replaced-method>  </bean>  

参考博客:http://jinnianshilongnian.iteye.com/blog/1415461,感谢大神的分享。

8 Bean的作用域
创建一个bean定义,其实质是用该bean定义对应的类来创建真正实例的“配方(recipe)”。把bean定义看成一个配方很有意义,它与class很类似,只根据一张“处方”就可以创建多个实例。你不仅可以控制注入到对象中的各种依赖和配置值。
这里写图片描述
可自定义bean的作用域,步骤如下:
8.1 继承org.springframework.beans.factory.config.Scope接口,接口中的方法说明:
第一个方法可以从作用域中获取对象。
Object get(String name, ObjectFactory objectFactory)

第二个方法可以从作用域中移除对象。例如,session作用域的实现可以从session中移除并返回session-scoped bean(如果没有找到相应名称的对象昂,则可以返回null)。
Object remove(String name)

第三个方法是注册作用域析构的回调方法,当作用域销毁或作用域中的某个对象销毁时候会执行。。
void registerDestructionCallback(String name, Runnable destructionCallback)

最后一个方法处理作用域的会话标识。对每一个作用域来说标识是不一样的。例如,对于session,将获得session标识。
String getConversationId()
8.2 使用自定义作用域
让Spring容器装配你的作用域,把一个新的Scope 注册到Spring 容器中的核心方法定义在ConfigurableBeanFactory接口中
void registerScope(String scopeName, Scope scope);
registerScope(..) 方法的第一个参数是一个作用域的唯一名称,例如,Spring 容器中的’singleton’和’prototype’。registerScope(..) 方法的第二个参数是你要注册和使用的自定义Scope的实例。
例如:

Scope customScope = new ThreadScope();beanFactory.registerScope("thread", scope);

使用作用域:

    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">        <property name="scopes">            <map>                <entry key="thread">                    <bean class="com.foo.ThreadScope"/>                </entry>            </map>        </property>    </bean>    <bean id="bar" class="x.y.Bar" scope="thread">        <property name="name" value="Rick"/>        <aop:scoped-proxy/>    </bean>    <bean id="foo" class="x.y.Foo">        <property name="bar" ref="bar"/>    </bean>

部分摘自官方文档。

未完待续。。。

原创粉丝点击