码农小汪-spring框架学习之2-spring IoC and Beans 控制反转 依赖注入 ApplicationContext BeanFactory

spring Ioc依赖注入控制反转

其实这个东西很好理解的,并不是那么的复杂。当某个Java对象,需要调用另一个Java对象的时候(被依赖的对象)的方法时。以前我们的做法是怎么做呢?主动的去创建被依赖的对象,然后调用被依赖的方法。或者是通过工厂的方法去获取依赖的对象,实质是一样的。这些都是主动的去创建被依赖的对象。然后使用spring框架之后,调用者,无需主动的去获取被依赖的对象,调用者只需要被动的去接受spring容器为调用者的成员变量赋值即可,spring会通过setter为成员赋值。调用者从原来的主动变为了被动的调用啦,所以称为控制反转。依赖注入没有啥子都差不多。这个东西没必要记得那么严格,只要自己晓得怎么去使用就好了。

  • The org.springframework.beans and org.springframework.context 包是Ioc的核心。
  • BeanFactory接口提供了一个能够管理任何类型的高级配置机制 对象。ApplicationContext是他的子类。ApplicationContext 它增加了容易集成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的话非常简单的就可以使用这些东西了,非常的速度,这个键值是快的要命。很多的配置文件啊,请你不要去记住他,简单的复制粘贴就好了,。但是你要理解机制,理解怎么去使用这些东西哦。多去看看文档,我们计算机专业的学生需要快速的学习能力,基本的东西,只要能使用就行了。

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

自动装配

不需要手动的注入依赖,感觉这种方式,不是太好。如果工程复杂,多个人开发,或者后期的人维护,带来的工作量太大了。真的不推荐。麻烦有麻烦的好处!

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值