spring學習之注入

前面幾個章節介紹了bean的定義,在一個完整的應用中,各個bean並非相互獨立的,而是一塊兒工做的,在spring中,經過注入來把這些獨立的bean串起來。java

基於構造方法的注入

XML

在xml配置文件中,是經過constructor-arg標籤來實現注入。
xml配置以下:spring

<?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="byType" class="com.learn.di.Person">
        <constructor-arg type="java.lang.String" value="張三"/>
        <constructor-arg type="int" value="18"/>
    </bean>

    <bean id="byName" class="com.learn.di.Person">
        <constructor-arg name="name" value="李四"/>
        <constructor-arg name="age" value="19"/>
    </bean>

    <bean id="byIndex" class="com.learn.di.Person">
        <constructor-arg index="0" value="王五"/>
        <constructor-arg index="1" value="20"/>
    </bean>

</beans>

person代碼:app

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

測試代碼ide

@Test
public void test() {
    ApplicationContext app = new ClassPathXmlApplicationContext("di.xml");
    Person person1 = app.getBean("byType",Person.class);
    Person person2 = app.getBean("byName",Person.class);
    Person person3 = app.getBean("byIndex",Person.class);
    System.out.println(person1);
    System.out.println(person2);
    System.out.println(person3);
}

運行結果以下:
image.png
第一個是經過類型注入,第二個是經過名稱注入,第三個是經過索引位置注入。函數

註解

在註解中,經常使用的註解是@Autowired。
MyService,MyController測試

@Service
public class MyService {
}
@Controller
public class MyController {
    MyService myService;

    public MyController(@Autowired MyService myService) {
        this.myService = myService;
    }
}

MyConfigthis

@Configuration
@ComponentScan(value="com.learn.annotation2")
public class MyConfig {

}

測試代碼:spa

@Test
public void test(){
    ApplicationContext app =  new AnnotationConfigApplicationContext(MyConfig.class);
    MyController myController=app.getBean("myController",MyController.class);
    System.out.println(myController.myService);
    System.out.println(app.getBean("myService"));
}

運行結果以下:
image.png
兩次打印的地址是同樣的,說明已經成功注入到myController中。若是想實現上面XML那種基本類型的注入,能夠用@Bean註解,經過return new一個對象來實現。3d

基於setter方法的注入

XML

di.xml配置以下:code

<?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="person2" class="com.learn.di.Person2">
        <property name="name" value="趙六"/>
        <property name="age" value="21"/>
    </bean>

</beans>

person2代碼以下:

public class Person2 {
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

測試代碼:

@Test
public void test2() {
    ApplicationContext app = new ClassPathXmlApplicationContext("di.xml");
    Person2 person2 = app.getBean("person2",Person2.class);
    System.out.println(person2);
}

運行結果以下:
image.png
不一樣於構造器注入,setter只能經過名稱注入。

ref

上面註解能夠直接注入容器的對象,在XML配置中,也可使用ref來注入。
di2.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">
    <import resource="di.xml"/>


    <bean id="persons" class="com.learn.di.Persons">
        <constructor-arg name="person1" ref="byName"/>
        <property name="person2" ref="byType"/>
    </bean>

</beans>

Persons代碼以下:

public class Persons {
    Person person1;
    Person person2;

    public Persons(Person person1) {
        this.person1 = person1;
    }

    public Person getPerson2() {
        return person2;
    }

    public void setPerson2(Person person2) {
        this.person2 = person2;
    }

    @Override
    public String toString() {
        return "Persons{" +
                "person1=" + person1 +
                ", person2=" + person2 +
                '}';
    }
}

運行結果以下:
image.png
ref後面的值,是bean的標識符。

p-namespace和c-namespace

dim5.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" xmlns:c="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person3" class="com.learn.di.Person3" c:tel="13800138000" p:name="張三" p:age="18"/>

</beans>

Person3

public class Person3 {
    private String name;
    private int age;
    private String tel;

    public Person3(String tel) {
        this.tel = tel;
    }

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

    @Override
    public String toString() {
        return "Person3{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", tel='" + tel + '\'' +
                '}';
    }
}

測試代碼:

@Test
public void test6() {
    ApplicationContext app = new ClassPathXmlApplicationContext("di5.xml");
    Person3 person3 = app.getBean("person3", Person3.class);
    System.out.println(person3);
}

運行結果
image.png
這種寫法,要引入xmlns:p和xmlns:c。p相對於property,c相對於constructor-arg。

註解

在註解中,方法名也不必定要setXXX,並且@Autowired支持直接在成員上面使用。
MyController

@Controller
public class MyController {
    @Autowired
    MyService myService;
    MyDao  myDao;

    @Autowired
    public void myDao(MyDao myDao) {
        this.myDao = myDao;
    }
}

測試代碼:

@Test
public void test(){
    ApplicationContext app =  new AnnotationConfigApplicationContext(MyConfig.class);
    MyController myController=app.getBean("myController",MyController.class);
    System.out.println(myController.myService);
    System.out.println(myController.myDao);
    System.out.println(app.getBean("myService"));
    System.out.println(app.getBean("myDao"));
}

運行結果以下:
image.png
兩次打印的地址是同樣的,說明已經成功注入到myController中。

構造器注入和setter注入

在系統中,咱們既能夠用構造器注入,也能夠用setter注入,甚至能夠兩種一塊兒用,均可以達到咱們想要的效果。
構造器注入:強依賴,大量的構造函數參數不是很優雅,沒法解決循環依賴的問題,會拋出BeanCurrentlyInCreationException異常。
setter注入:可選依賴,能夠從新注入。

內部類注入

di3.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="outer" class="com.learn.di.Outer">
        <property name="inner">
            <bean class="com.learn.di.Outer.Inner">
                <property name="name" value="張三"/>
                <property name="age" value="18"/>
            </bean>
        </property>
    </bean>

</beans>

Outer類

public class Outer {
    private Inner inner;

    public Inner getInner() {
        return inner;
    }

    public void setInner(Inner inner) {
        this.inner = inner;
    }

    static class Inner{
        private String name;
        private int age;

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

        @Override
        public String toString() {
            return "Inner{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

    @Override
    public String toString() {
        return "Outer{" +
                "inner=" + inner +
                '}';
    }
}

測試代碼

@Test
public void test4() {
    ApplicationContext app = new ClassPathXmlApplicationContext("di3.xml");
    Outer outer = app.getBean("outer", Outer.class);
    System.out.println(outer);
}

運行結果:
image.png
內部類的bean定義,不須要id和name。由於是內部類,因此即使設置了,容器也會忽略。

集合

di4.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="abstractCollect" abstract="true" class="com.learn.di.AbstractCollect">
        <property name="list">
            <list merge="true">
                <value>aaa</value>
                <value>bbb</value>
                <value>ccc</value>
            </list>
        </property>
        <property name="map">
            <map merge="true">
                <entry value="name" key="張三"/>
                <entry value="age" key="18"/>
            </map>
        </property>
        <property name="set">
            <set merge="true">
                <value>aaa</value>
                <value>bbb</value>
                <value>ccc</value>
            </set>
        </property>
        <property name="properties">
            <props merge="true">
                <prop key="name">李四</prop>
                <prop key="age">20</prop>
            </props>
        </property>
    </bean>

    <bean id="collect" class="com.learn.di.Collect" parent="abstractCollect">
        <property name="list">
            <list merge="true">
                <value>ddd</value>
                <value>eee</value>
                <value>fff</value>
            </list>
        </property>
        <property name="map">
            <map merge="true">
                <entry value="name" key="王五"/>
                <entry value="age" key="19"/>
            </map>
        </property>
        <property name="set">
            <set merge="true">
                <value>ddd</value>
                <value>eee</value>
                <value>fff</value>
            </set>
        </property>
        <property name="properties">
            <props merge="true">
                <prop key="sex">男</prop>
                <prop key="tel">13800138000</prop>
            </props>
        </property>
    </bean>

</beans>

AbstractCollect和Collect

public abstract class AbstractCollect  {
    List<String> list;
    Set<String> set;
    Map<String,String> map;
    Properties properties;

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public Set<String> getSet() {
        return set;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public Map<String, String> getMap() {
        return map;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "AbstractCollect{" +
                "list=" + list +
                ", set=" + set +
                ", map=" + map +
                ", properties=" + properties +
                '}';
    }
}
public class Collect extends AbstractCollect{

}

測試類:

@Test
public void test5() {
    ApplicationContext app = new ClassPathXmlApplicationContext("di4.xml");
    Collect collect = app.getBean("collect", Collect.class);
    System.out.println(collect);
}

運行結果以下:
image.png
merge爲true且設置了parent的時候,能夠繼承父類的信息。merge的時候,必須是同一類型的對象。

其餘

空值的處理

若是是空字符串,如下是等同的。

<bean class="ExampleBean">
    <property name="email" value=""/>
</bean>
exampleBean.setEmail("");

若是是null,如下是等同的。

<bean class="ExampleBean">
    <property name="email">
        <null/>
    </property>
</bean>
exampleBean.setEmail(null);

depends-on和@DependsOn

當A對象包含B對象的時候,A對象初始化時,B對象必須初始完成。若是A對象沒有包含B對象,也須要B對象初始化完成後,才初始化A,那能夠用depends-on。
di6.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" xmlns:c="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="one" class="com.learn.di.One" depends-on="two"/>
    <bean id="two" class="com.learn.di.Two"/>

</beans>

One和Two

public class One {
    public One(){
        System.out.println("one init");
    }
}
public class Two {
    public Two(){
        System.out.println("two init");
    }
}

測試代碼

@Test
public void test7() {
    new ClassPathXmlApplicationContext("di6.xml");
}

當有depends-on="two"的時候,運行結果以下:
image.png
不然運行結果以下
image.png說明depends-on生效了。@DependsOn這邊就不作例子了。

相關文章
相關標籤/搜索