spring 是一个轻量级(不需要继承啊,实现啊就能使用)的控制反转(IoC)和面向切面的容器框架。
本文基于spring 4.1.6

导入需要包

1.spring-core.jar
2.spring-benas.jar
3.spring-context.jar
4.spring-expression.jar
5.commons-logging  
    注:这个不是spring的包而是spring依赖的包。(spring开发者调用别人写好的包。如下面的源码)
    ![Spring源码](https://img-blog.csdn.net/20170424174132241?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdjVfQkFU/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![Spring模块](https://img-blog.csdn.net/20170424173534078?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdjVfQkFU/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
可见和我们要将核心容器相关的jar导入。(就是上面前四个)

Spring 是模块化的,用到什么导入什么。

控制反正IoC

等同于依赖注入
为了避免对象之间复杂的关系而使得程序高耦合。为了解决这个问题所以有了IoC.
IoC为协调各个组件间的依赖关系,使用动态的注入(可以理解为赋值)从而是的代码低耦合,扩展性更好。
由原先的 new 一个对象,变成现在的容器装配。
代码分析
再经典不过的例子Helloword
新建一个java工程
src 下建立如下 HelloWord  javaBean
package Test;

public class HelloWord {

    private String content;
    public String getContent() {
        System.out.println("getcontent way run ..");
        return content;
    }

    public void setContent(String content) {
        this.content = content;
        System.out.println("setcontent way run ..");
    }
    public HelloWord() {
        System.out.println("  hellowrod  constructor  run..." +content);    
    }
    public void hello(){
        System.out.println(content);
    }
}

在src 新建一个 Spring Bean Configuration File 名字为 beansContext.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">


</beans>
我们要做的就是在<beans></beans> 添加<bean>
<?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">

<!--id:可以理解为容器为我们创建对象的引用 class:一看是全类名,八九不离十是容器使用反射帮我们创建对象(默认当然是找无参构造器所以在没有指定的情况下要有无参构造器) -->
<bean id="helloWord" class="Test.HelloWord">
<!--property 由于对属性赋值  name:跟属性名 value:跟要给的值 -->

    <property name="content" value="helloword"></property>
</bean>

</beans>

注:这里在多说几句 property 赋值是通过setXXX来赋值的。在源码中将name 的值拿到通过改变首字母大写再在前面加上set得到方法名去调用方法传入value.(本例中就是 content->Conent->setContent).

写一个测试方法

package Test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {

        ApplicationContext ioc=new ClassPathXmlApplicationContext("beansContext.xml");
        HelloWord hw=(HelloWord) ioc.getBean("helloWord");
        hw.hello();

    }
}

见证奇迹的时刻到了。控制台不仅打印了helloword 和 方法执行时sysout 还有一大片的信息。
正如前面所说的我们为什么要加入logging包 就是spring有调用日志方法。

当我们把

//HelloWord hw=(HelloWord) ioc.getBean("helloWord");
    //  hw.hello();

这两行注释掉又发现有趣的现象,尽然还执行了 构造器 和set 方法。这是因为 默认情况下ApplicationContext 启动时将实例化所有的singleton bean.
先解释singleton: bean 节点除了 id、 class 还有scope 、factory-bean、factory-method 属性
而这里的singleton 就是scope的属性值 作用就是在容器中共享一个bean 实例。什么意思呢。用代码说明直接一点。

<bean id="helloWord" class="Test.HelloWord" scope="singleton">
    <property name="content" value="helloword"></property>
</bean>

先加上scope 属性

package Test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {

        ApplicationContext ioc=new ClassPathXmlApplicationContext("beansContext.xml");
        HelloWord hw=(HelloWord) ioc.getBean("helloWord");
        HelloWord hw2=(HelloWord) ioc.getBean("helloWord");
        System.out.println(hw2==hw);

    }
}

结果为true
而如果吧属性值改为 prototype恰恰相反 相同的代码结果为false;

依赖注入

依赖注入的方式:属性注入 构造器注入
属性注入
    就是上面我们使用的方法通过 property 来注入
构造器注入
    使用<constructor-arg> 能用代码解决的事情绝对不多说。上代码
简单的person  bean
package Test;

public class Person {

    private String name;
    private int age;
    private Person parent;
    public Person(String name){
        this.name=name;
    }
    public Person(String name,int age){
        this(name);
        this.age=age;
    }
    public Person(String name,int age,Person parent){
        this(name,age);
        this.parent=parent;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Person getParent() {
        return parent;
    }
    public void setParent(Person parent) {
        this.parent = parent;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", parent=" + parent
                + "]";
    }

}

新建一个personContext.xml用于注入(也可以在之前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="son" class="Test.Person" depends-on="father">
    <constructor-arg value="张三" index="0"></constructor-arg>
    <constructor-arg value="3" type="int"></constructor-arg>
    <constructor-arg ref="father"></constructor-arg>
</bean>

<bean id="father" class="Test.Person" lazy-init="true" >
    <constructor-arg value="张二" index="0"></constructor-arg>
    <property name="parent" ><null/></property>
</bean>

</beans>

看第一个bean 就是使用构造方法备注属性同时也可以发现 Person中没有 无参构造器但是没有错。就是前面说的 默认为无参构造器除非指定 。 这里的指定就是使用 constructor-arg 。
看一下结果

Person [name=张三, age=3, parent=Person [name=张二, age=0, parent=null]]
善于观察的人会发现father不是延迟加载吗 怎么加载了。这里存在依赖关系 son有引用是 father是所以使用到了当然要加载。延迟加载是不会在没有用到的情况下自动加载。而这里使用到了。

还有一点depends-on好像没什么用。是这样的我吗看看结果中 “张二”的parent=null 如果在第二个bean中加上depends-on 则不能为null 了必须要有依赖的bean。

住:null 在这里的写法是上面的写法 另外在补充特殊字符的写法比如要显示> 《![CDATA[hh>]]》(这里由于不能打尖括号就用汉语的双括号代替了)

有时还会遇到给List map set这样的集合赋值 怎么办呢:

<bean id="father" class="Test.Person" lazy-init="true" >
    <constructor-arg value="张二" index="0"></constructor-arg>
    <property name="parent" ><null/></property>
    <property name="list">
        <list>
            <value>this is list</value>
        </list>
    </property>
    <property name="map">
        <map>
            <entry>
                <key>
                    <value>this is key</value>

                </key>
                <value>this is map value</value>
            </entry>
        </map>
    </property>
    <property name="set">
        <set>
            <value>this is set</value>
        </set>
    </property>
</bean>

bean 属性 补充

刚刚我们看到了scope 属性的应用现在再补充一下其他的属性
1.lazy-init 延迟初始化bean
这不难让我们联想到懒汉式设计模式。当用到的时候在初始话。这样对于一些加载需要耗费大量资源的bean会很有用。
2.depend-on : 依赖的对象不能为null

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐