码农小汪-spring框架学习之2-spring IoC and Beans 控制反转 依赖注入 ApplicationContext BeanFactory spring Ioc依赖注入控制反转 配置和使用 Bean的实例化 依赖关系 Dependencies 注入依赖例子 内部Bean 集合属性的注入 自己主动装配

事实上这个东西很好理解的,并非那么的复杂。

当某个Java对象,须要调用还有一个Java对象的时候(被依赖的对象)的方法时。曾经我们的做法是怎么做呢?主动的去创建被依赖的对象,然后调用被依赖的方法。

或者是通过工厂的方法去获取依赖的对象,实质是一样的。

这些都是主动的去创建被依赖的对象。然后使用spring框架之后,调用者,无需主动的去获取被依赖的对象,调用者仅仅须要被动的去接受spring容器为调用者的成员变量赋值即可,spring会通过setter为成员赋值。调用者从原来的主动变为了被动的调用啦,所以称为控制反转。依赖注入没有啥子都差点儿相同。这个东西不是必需记得那么严格,仅仅要自己晓得怎么去使用就好了。

  • The org.springframework.beans and org.springframework.context 包是Ioc的核心。

  • BeanFactory接口提供了一个能够管理不论什么类型的高级配置机制 对象。

    ApplicationContext是他的子类。ApplicationContext 它添加了easy集成Spring的AOP 功能;信息资源处理(用于国际化),事件 出版,和应用程序层特定上下文等WebApplicationContext在web应用程序中使用

  • 简而言之,BeanFactory提供的配置和基本框架 功能,ApplicationContext添加了许多其它的特定的功能。 的ApplicationContext是一个完整的超集的BeanFactory使用,
  • A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.

配置和使用

  • 配置元数据准备
    基于注解的配置:Spring 2.5引入了 对基于注解的配置元数据的支持
    基于java的配置:从Spring 3.0開始,许多功能 提供的Spring JavaConfig项目成为Spring框架的核心的一部分。 因此您能够定义bean使用Java,而外部应用程序类 比XML文件。 使用这些新特性,请參阅@Configuration,@Bean,@Import和@DependsOn
    我个人还是比較喜欢注解,@Resource 这个关键字在我这次的使用中使用的特别的多。很的方便使用!


    XML-based configuration metadata shows these beans configured as < bean/> elements inside a top-level < beans/> element. Java configuration typically uses @Bean annotated methods within a @Configuration class.

这个是我们配置文件的基本结构,使用MyExclipse的话很easy的就能够使用这些东西了,很的速度,这个键值是快的要命。许多的配置文件啊,请你不要去记住他。简单的复制粘贴就好了。。

可是你要理解机制,理解怎么去使用这些东西哦。

多去看看文档,我们计算机专业的学生须要高速的学习能力,主要的东西,仅仅要能使用即可了。

<?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="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here --> </beans>
  • 实例化容器 Instantiating a container
    这个很的简单,哈哈!

    我这次測试的时候使用的比較的多,喜欢上了測试这个玩意很的简单并且方便哈哈。须要让我们的每个模块都正确啦,再次集成起来的时候就不会出现重大的问题之类的东西!模块化的思想很重要。这个是一个程序猿不断成长进步的一个很好的证据

ApplicationContext context =
    new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});

这个仅仅是一种方法,你能够使用许多地方的XML配置文件。可是我自己还是喜欢就写一个放在我们的项目的路径下就好了。

其它的嘛,由于开发的时候可能就是不止你一个人在处理这些事情啦,或许有许多的人,分开工作,使用不同的配置文件。集成起来的时候才会特别的简单和方便,这些都市很有必要的,往往是一些小的时候把,你也能够把不同的模块写在不同的地方。比方Dao层 Service层…这个也是能够的。自己任意
然后使用 import 就能够把他们集成进来了,和Java的有点像。你是不是也是感觉到了

beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>

    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>

使用的话,context.getBean(XXX)。

这样就好了,很的方便。就和我们使用New简直是就是没得差别来着的,这么讲我相信你是很的理解的。

就是一种形式嘛,这个工厂中获得对象的一个方法而已,就是这么的简单何必想得这么的复杂呢。

假设自己想去了解源代码,自己看即可啦,学习的方式多种多样,自己有自己的一套。


  • Naming beans
    bean的命名,直接简单的Id就好了,都不要一样的。也能够有别名,使用Name属性,多个别名使用逗号隔开就好了。

    这里为啥要使用别名呢?我们举个例子你就知道了

一个类持有一个本类的实例作为属性

public class SomeBean {
//注意看这个属性。就是本类
    private SomeBean someBean;
    public SomeBean(){}
    public void setSomeBean(SomeBean someBean) {
        this.someBean = someBean;
    }
}

这个时候就是很的管用啦!

<?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 的别名,使用,/;/空格 分隔都是能够是--> <bean id="someBeanId" name="someBean,someBeanA;someBeanB someBeanC" class="com.example.spring.bean.SomeBean"> <!--将别名为 someBeanA 的 bean 注入给 id 为 someBeanId 的 bean 的属性 'someBean'--> <property name="someBean" ref="someBeanA"></property> </bean> </beans>

除了上面的这样的方式之外呢,还能够使用,以下的这样的方式也是能够的,事实上都是差点儿相同的!

Bean的实例化

通常。通过指定 bean 的 class 属性,容器使用反射调用其构造函数直接创建 bean,有点像 Java 编码中使用 new 操作符
指定 class 实际类含实用于创建对象的静态工厂方法。这是不常使用的场景。容器会调用类的静态工厂方法创建 bean。调用静态工厂方法返回的对象类型或许是同样类型,或许全然是其它类。
第一种的方式就是以下这样的,通过无慘够造方法。反射机制够造对象

<bean id="exampleBean" class="examples.ExampleBean"/>

<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

另外一种,通过我们的静态工工厂的方法够造我们的对象

<bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>
public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService() {}

    public static ClientService createInstance() {
        return clientService;
    }
}

还有第三种初始化实例方法Instantiation using an instance factory method,和另外一种差点儿相同,仅仅是如今创建对象的不是静态的方法啦

<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
    <!-- inject any dependencies required by this locator bean -->
</bean>

<!-- the bean to be created via the factory bean -->
<bean id="clientService"
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>
public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();
    private DefaultServiceLocator() {}

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}

依赖关系 Dependencies

依赖注入(DI)。是一个有对象定义依赖的手法,也就是。怎样与其它对象合作,通过构造參数、工厂方法參数、或是在对象实例化之后设置对象属性,实例化既能够构造也能够是使用工厂方法。容器在它创建 bean 之后注入依赖。这个过程从根本上发生了反转,因此又名控制反转( Ioc),由于 Spring bean自己控制依赖类的实例化或者定位 。 Spring bean 中就有依赖类的定义,容器使用依赖类构造器创建依赖类实例。使用 Service Locator 模式定位依赖类

DI 有 2 种主要方式。 构造注入 和 setter 注入

  • 构造注入 < constructor-arg/>元素。

package x.y;

public class Foo {

    public Foo(Bar bar, Baz baz) {
        // ...
    }

}
<beans>
    <bean id="foo" class="x.y.Foo">
        <constructor-arg ref="bar"/>
        <constructor-arg ref="baz"/>
    </bean>

    <bean id="bar" class="x.y.Bar"/>

    <bean id="baz" class="x.y.Baz"/>
</beans>

Use the index attribute to specify explicitly the index of constructor arguments. For example: 使用index差别我们的够造函数的使用的位置

package examples;

public class ExampleBean {

    // Number of years to calculate the Ultimate Answer
    private int years;

    // The Answer to Life, the Universe, and Everything
    private String ultimateAnswer;

    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }

}
<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" value="42"/>
</bean>

也能够使用Name

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg name="ultimateanswer" value="42"/>
</bean>
  • Setter-based依赖注入,我自己感觉这样的使用频率很的多。可是我自己一般都是使用注解的方式往哪里面放,XML和注解集合起来使用哈哈。


    使用何种依赖注入方式,对于某些类,很有意义。有时协同没有源代码。由你来决定使用何种方式。

    比方,第三方类未暴露法,那么构造注入或许就是唯一的可行的注入方式了。

循环依赖 假设你主要使用构造注入,可能会创建一个循环依赖,该依赖不能解析。先有鸡再有蛋啊,这个是一个原则问题,我们不能够避免的!这就是为什么 ApplicationContext 默认会预先实例化单例 bean。在这些 bean 被实际请求之前就创建,会消耗一些时间和内存,可是在 ApplicationContext 创建后你就能发现配置问题,这时候就不能启动啦!

注入依赖例子

<bean id="exampleBean" class="examples.ExampleBean">
    <!-- setter injection using the nested <ref/> element -->
    <property name="beanOne">
        <ref bean="anotherExampleBean"/>
    </property>

    <!-- setter injection using the neater ref attribute -->
    <property name="beanTwo" ref="yetAnotherBean"/>
    <property name="integerProperty" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {

    private AnotherBean beanOne;
    private YetAnotherBean beanTwo;
    private int i;

    public void setBeanOne(AnotherBean beanOne) {
        this.beanOne = beanOne;
    }

    public void setBeanTwo(YetAnotherBean beanTwo) {
        this.beanTwo = beanTwo;
    }

    public void setIntegerProperty(int i) {
        this.i = i;
    }

}

The following example uses constructor-based DI: 够造函数中引用别的对象。这个和属性是别的对象是一样的,写的方式不一样而已。

<bean id="exampleBean" class="examples.ExampleBean">
    <!-- constructor injection using the nested <ref/> element -->
    <constructor-arg>
        <ref bean="anotherExampleBean"/>
    </constructor-arg>

    <!-- constructor injection using the neater ref attribute -->
    <constructor-arg ref="yetAnotherBean"/>

    <constructor-arg type="int" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {

    private AnotherBean beanOne;
    private YetAnotherBean beanTwo;
    private int i;

    public ExampleBean(
        AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
        this.beanOne = anotherBean;
        this.beanTwo = yetAnotherBean;
        this.i = i;
    }

}

看上去也不是特别的难吧。我们要慢慢的尝试在框架的机制下编程,而不是坐井观天~

内部Bean

<bean id="outer" class="...">
    <!-- instead of using a reference to a target bean, simply define the target bean inline -->
    <property name="target">
        <bean class="com.example.Person"> <!-- this is the inner bean -->
            <property name="name" value="Fiona Apple"/>
            <property name="age" value="25"/>
        </bean>
    </property>
</bean>

An inner bean definition does not require a defined id or name; 不要定义名字id the container ignores these values. It also ignores the scope flag. Inner beans are always anonymous and they are always created with the outer bean. It is not possible to inject inner beans into collaborating beans other than into the enclosing bean.不能给别的注入依赖

集合属性的注入

In the < list/>, < set/>, < map/>, and < props/> elements, you set the properties and arguments of the Java Collection types List, Set, Map, and Properties, respectively. 我在想啊,我们从数据库中取的东西没得必要这么处理吧!这样的动态的东西,无法直接通过这样的死方式放进入,还是须要使用编程的手段使用的!

<bean id="moreComplexObject" class="example.ComplexObject">
    <!-- results in a setAdminEmails(java.util.Properties) call -->
    <property name="adminEmails">
        <props>
            <prop key="administrator">administrator@example.org</prop>
            <prop key="support">support@example.org</prop>
            <prop key="development">development@example.org</prop>
        </props>
    </property>
    <!-- results in a setSomeList(java.util.List) call -->
    <property name="someList">
        <list>
            <value>a list element followed by a reference</value>
            <ref bean="myDataSource" />
        </list>
    </property>
    <!-- results in a setSomeMap(java.util.Map) call -->
    <property name="someMap">
        <map>
            <entry key="an entry" value="just some string"/>
            <entry key ="a ref" value-ref="myDataSource"/>
        </map>
    </property>
    <!-- results in a setSomeSet(java.util.Set) call -->
    <property name="someSet">
        <set>
            <value>just some string</value>
            <ref bean="myDataSource" />
        </set>
    </property>
</bean>

map.key, map.value,或者 set.value。以能够是以下元素 bean | ref | idref | list | set | map | props | value | null。不然我们的Map是个对象怎么办呢。你说是不是啊?

Collection merging,这个就是属性还能够有父子,能够是抽象的,哈哈还能够合并呢!

<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>

Notice the use of the merge=true attribute on the element of the adminEmails。这里回合并在一起的哦
administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk 这个是结果啦啦~

list不能合并。详细原因好像是由于合并的那个接口中没有实现List的接口,我也不是和清楚,这个对于 我们的使用没有影响的,我们很少会使用到合并这样的东西的!

null值得表示 and Empty value

<bean class="ExampleBean">
    <property name="email" value=""/>
</bea
<bean class="ExampleBean">
    <property name="email">
        <null/>
    </property>
</bean>

还有P空间~我认为不是必需学啦~我们是刚開始学习的人,学会一种表达方式即可了。

何必弄的这么麻烦,假设你看到别人的项目中有这么写的话,看不懂,那么百度一下就好了。这个我相信你有这个能力去处理这些事情。

depends on 在初始化这个之前的先决条件。我要在这些处理好了我才干够初始化

假设一个bean的依赖还有一个通常意味着一个bean设置 还有一个的属性。必须先要初始化才干够。比方我们的数据库驱动程序,必须先啊!这里必须先初始化两个才干够进行下一步的操做啊!

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
    <property name="manager" ref="manager" />
</bean>

<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />

Lazy-initialized beans 延迟初始化

ApplicationContext 的各种实现默认的初始化处理过程,都是尽早的创建、配置全部的单例 bean。

通常,这样的预先实例化是很好的,由于在配置的错误或者环境问题立马就能暴露出来,而不是数小时甚至数天后才发现。若不须要此行为,能够通过设置 lazy-initialized 延迟载入来阻止预先初始化。 lazy-initializedbean 告诉 Ioc 容器,仅仅有在第一次请求的时候採取初始化。而不是在启动容器时初始化。

like this

<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.foo.AnotherBean"/>

容器级别的延迟初始化也是能够的

<beans default-lazy-init="true">
    <!-- no beans will be pre-instantiated... -->
</beans>

自己主动装配

不须要手动的注入依赖。感觉这样的方式。不是太好。假设project复杂,多个人开发,或者后期的人维护。带来的工作量太大了。真的不推荐。麻烦有麻烦的优点。

排除自己主动装配 bean
在每个 bean 的设置中,你能够排除 bean 用于自己主动装配。 XML 配置中,设置< bean/>元素的 autowire-candidate 属性为 false。容器将不使用该 bean 自己主动装配。(包含注解配置,像@Autowired)