Spring Framework02-IOC基本使用

經過上篇文章大概知道ioc、DI的概念了,下面咱們詳細介紹一下java

1、Spring IOC建立對象

IOC經過上文的介紹做用是控制建立對象的解釋權,咱們把代碼從新看一下mysql

//User.java
public class User {
    private String username;
    private String password;
    
     /**
 	* 省略有參無參構造器,getter/setter方法
 	*/
}

咱們也不建立dao、service類了,直接就用這個User類來測試spring

配置文件:applicationContext.xmlsql

<?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:建立的bean的惟一標識,做用是區分其它的bean
       class:建立的對象的全限定名(包名+類名)      -->
<bean id="user" class="com.ty.bean.User"></bean>
    
</beans>
  1. bean的id獲取IOC容器中的對象
//測試文件
public class MyTest {
     ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
    @Test
    public void test1(){
        User user = (User) context.getBean("user");
        System.out.println(user);
    }
}

這是IOC建立對象的第一種方式即經過bean的id獲取IOC容器中的對象:context.bean("配置文件bean中的id")數據庫

還有另外兩種方式 :session

  1. 經過bean的類型獲取對象:context.bean(注入對象的class類型)
@Test
    public void test2(){
        User user = context.getBean(User.class);
        System.out.println(user);
    }

這種注入方法有劣勢,即:配置文件中有多個同類型的bean(即class重複)時,注入對象就會報錯,例如:app

<?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:建立的bean的惟一標識,做用是區分其它的bean
       class:建立的對象的全限定名(包名+類名)      -->
<bean id="user" class="com.ty.bean.User"></bean>
<bean id="use2" class="com.ty.bean.User"></bean>
    
</beans>

再接着運行測試文件的時候就會報NoUniqueBeanDefinitionException異常ide

  1. 經過bean的id和類型獲取對象:context.bean("配置文件bean中的id",注入對象的class類型)
@Test
    public void test3(){
        User user = context.getBean("user",User.class);
        System.out.println(user);
    }

2、SpringDI注入

光建立對象沒用,最重要的仍是爲對象賦值,咱們說過DI是IOC的實現,DI更能經過代碼體現出來,接下開咱們依次介紹幾種賦值方式post

一、屬性注入(即setter注入)

1)簡單類型(基本類型+String類型)
<bean id="user" class="com.ty.bean.User">
        <!--  property:表示屬性注入
              name:屬性的名字,實際上是常規bean中set以後的名字(首字母小寫)
              value:屬性值     -->
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>
2)複雜類型(引用類型)
public class Address {
    private String city; 
    
     /**
 	* 省略有參無參構造器,getter/setter方法
 	*/
}


public class User {
    private String username;
    private String password;
    private String[] hobby;
    private Address address;
    private List list;
    private Set set;
    private Map map;
    private Properties properties;

      /**
 	* 省略有參無參構造器,getter/setter/toString方法
 	*/
}
<!-- private String[] hobby   -->
        <property name="hobby">
            <array>
                <value>吃飯</value>
                <value>看電影</value>
                <value>打遊戲</value>
                <!--  表示賦空值,能夠起佔位做用-->
                <null></null>
            </array>
        </property>
<!--private Address address- 能夠有2種注入方式,一種方式在property標籤嵌套一個bean-->
<!--        <property name="address">-->
<!--            <bean class="com.ty.bean.Address">-->
<!--                <property name="city" value="大連"></property>-->
<!--            </bean>-->
<!--        </property>-->

		             <!--ref:引用的bean的id-->
        <property name="address" ref="address"></property>
<!--   private List list-->
        <property name="list">
            <list>
                <value>a</value>
                <value>b</value>
                <value>c</value>
            </list>
        </property>
 <!--   private Set set-->
        <property name="set">
            <set>
                <value>redio</value>
                <value>book</value>
                <value>game</value>
            </set>
        </property>
  <!--   private Map map-->
        <property name="map">
            <map>
                <entry key="1" value="北京"></entry>
                <entry key="2" value="上海"></entry>
                <entry key="3" value-ref="address"></entry>
            </map>
        </property>
   <!--  private Properties properties-->
        <property name="properties">
            <props>
                <prop key="username">root</prop>
                <prop key="password">root</prop>
            </props>
        </property>
    </bean>

<bean id="address" class="com.ty.bean.Address">
        <property name="city" value="大連"></property>
    </bean>

List,Set,Map,Properties中還有一種注入方式,即util命名方式,主要的做用:方便別人引用測試

util命名空間方式
<!--   private List list-->
        <property name="list" ref="mylist"></property>
 <!--   private Set set-->
        <property name="set" ref="myset"></property>
 <!--   private Map map-->
        <property name="map" ref="mymap"></property>
 <!--  private Properties properties-->
        <property name="properties" ref="myproperties"></property>
    </bean>

    <util:list id="mylist">
        <list>
            <value>a</value>
            <value>b</value>
            <value>c</value>
        </list>
    </util:list>

    <util:set id="myset">
        <set>
            <value>redio</value>
            <value>book</value>
            <value>game</value>
        </set>
    </util:set>

    <util:map id="mymap">
        <entry key="1" value="北京"></entry>
        <entry key="2" value="上海"></entry>
        <entry key="3" value-ref="address"></entry>
    </util:map>

    <util:properties id="myproperties">
        <prop key="username">root</prop>
        <prop key="password">root</prop>
    </util:properties>
3)P 命名空間方式

除了上方util命名空間方式以外搭配着還有一個P命名空間

<bean id="user2" class="com.ty.bean.User" p:username="root" p:password="123456" p:address-ref="address" p:list-ref="mylist"></bean>
4)自動注入

能夠按照必定規則進行裝配注入,不用具體指定爲某個屬性賦值,在工廠中查找一個bean,爲屬性注入屬性值。

<bean id="address" class="com.ty.bean.Address">
        <property name="city" value="上海"></property>
</bean>

<bean id="person" class="com.ty.bean.Person" autowire="byName"></bean>
  1. byName:按照bean的id進行裝配

  2. byType:按照bean的類型來進行注入,可是若是有多個相同類型,就會報錯,不知道選擇哪個具體的類型

二、構造器注入

public class User {
    private String username;
    private String password;

   /**
 	* 省略有參無參構造器,getter/setter方法
 	*/
}
<bean id="user3" class="com.ty.bean.User">
     <!--構造注入的constructor-arg標籤裏還有幾個屬性
		name:形參列表的名稱
		value:實參的值
		type:參數類型
		index:參數索引,從0開始
-->
        <constructor-arg name="username" value="root"></constructor-arg>
        <constructor-arg name="password" value="123456"></constructor-arg>
    </bean>

屬性注入有P命名空間,構造器注入有C命名空間

1)C 命名空間
<bean id="user4" class="com.ty.bean.User" c:username="root" c:password="123456"></bean>
2)自動注入
<bean id="person" class="com.ty.bean.Person" autowire="constructor"></bean>
  1. constructor:使用構造器注入,形參列表必需要有對應 bean 對象

3、bean對象之間的關係

一、繼承關係

<bean id="parent" class="com.ty.bean.User">
        <property name="username" value="root"></property>
    </bean>
<!--parent:指定繼承的bean信息-->
    <bean id="son" class="com.ty.bean.User" parent="parent"></bean>

二、抽象關係

這個是在繼承關係的父bean裏添加abstract屬性,這個做用就是該bean是否能實例化

<bean id="parent" class="com.ty.bean.User" abstract="true">
        <property name="username" value="root"></property>
    </bean>

三、依賴關係

這個就是bean的前後建立順序,depends-on依賴哪一個bean就誰先建立誰,而後再建立本對象

<bean id="user5" class="com.ty.bean.User" depends-on="address"></bean>

<bean id="address" class="com.ty.bean.Address">
        <property name="city" value="大連"></property>
    </bean>

4、bean對象的做用域

經過scope屬性指定當前bean的做用域,有四個值

singleton:單例模式,從IOC容器中獲取的都是同一個對象,默認的做用域

prototype:多例模式,從IOC容器中獲取的對象每次都是新建立

request:每次發送請求都會有一個新的對象

session:每一次會話都會有一個新的對象

<bean id="user5" class="com.ty.bean.User" scope="singleton"></bean>

ps:singleton做用域:每次在建立IOC容器完成以前此對象已經建立完成,即:

ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");

​ prototype做用域:每次是在須要用到此對象的時候纔會建立,即

User user = (User) context.getBean("user");

5、工廠對象

靜態工廠

工廠自己不須要建立對象,可是能夠經過靜態方法調用,對象=工廠類.靜態工廠方法名();

public class PersonStaticFactory {
    public static Person getInstance(String name){
        Person person=new Person();
        person.setId(1001);
        person.setAge(18);
        person.setName(name);
        return person;
    }
}
<!--靜態工廠:類名.靜態方法()--> 
<bean id="person" class="com.ty.factory.PersonStaticFactory" factory-method="getInstance">
        <constructor-arg value="jack"></constructor-arg>
    </bean>
實例工廠

工廠自己須要建立對象,工廠類 工廠對象=new 工廠類;工廠對象.get對象名();

public class PersonInstanceFactory {
    public Person getInstance(String name){
        Person person=new Person();
        person.setId(1001);
        person.setAge(18);
        person.setName(name);
        return person;
    }
}
<!--實例工廠:先建立工廠實例,而後調用工廠實例的方法
        factory-bean:表示具體工廠類的實例
        factory-method:表示具體工廠實例的方法
    -->
<bean id="factory" class="com.ty.factory.PersonInstanceFactory"></bean>
    <bean id="person" class="com.ty.bean.Person" factory-bean="factory" factory-method="getInstance">
        <constructor-arg value="jack"></constructor-arg>
    </bean>
繼承FactoryBean

FactoryBean是Spring規定的一個接口,當前接口的實現類,Spring都會將其做爲一個工廠,可是在ioc容器啓動的時候不會建立實例,只有在使用的時候纔會建立對象

public class MyFactoryBean implements FactoryBean {
    /**
     * 此方式是spring建立bean方式的一種補充,用戶能夠按照需求建立對象, 建立的對象交由spring IOC容器來進行管理,不管是不是單例,都是在用到的時候纔會建立該對象,不用該對象不會建立
     */
    @Override
    public Person getObject() throws Exception {		//建立的對象
        Person person=new Person();
        person.setId(1001);
        person.setName("jack");
        person.setAge(20);
        return person;
    }

    @Override
    public Class<?> getObjectType() {		//返回對象的類型		
        return Person.class;
    }

    @Override
    public boolean isSingleton() {			//是否單例
        return true;
    }
}
<bean id="factoryBean" class="com.ty.factory.MyFactoryBean"></bean>

6、bean對象的對象的生命週期

建立
  • scope="singleton"(不配置lazy-init="true"屬性),每次在建立IOC容器完成以前此對象已經建立完成
  • scope="prototype",每次是在須要用到此對象的時候建立(scope="singleton"配置lazy-init="true"屬性也是這樣)
初始化

在對象建立完成以後會調用初始化方法

  1. 實現InitializingBean接口

    //實現這個方法,完成初始化操做
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("afterPropertiesSet");
        }
  2. 對象中提供一個普通的方法同時配置Spring配置文件:

    public void init(){
            System.out.println("init");
    }
    <bean id="p" class="com.ty.bean.Person" init-method="init"></bean>

    順序:對象的注入-》InitializingBean-》普通init-method

銷燬
  1. 實現DisposableBean接口
@Override
    public void destroy() throws Exception {
        System.out.println("destory");
    }
  1. 定義一個普通的銷燬方法同時配置Spring配置文件
public void mydestory(){
        System.out.println("mydestory");
    }
<bean id="p" class="com.ty.bean.Person" scope="prototype" init-method="init" destroy-method="mydestory">
        <property name="id" value="1001"></property>
    </bean>

銷燬方法只會在scope="singleton"時纔會調用,並且須要對象關閉,例如:context.close()

7、配置bean對象初始化方法的先後處理方法

spring中包含一個BeanPostProcessor的接口,能夠在bean的初始化方法的先後調用該方法,若是配置了初始化方法的前置和後置處理器,不管是否包含初始化方法,都會進行調用

public class MyBeanPostProcessor implements BeanPostProcessor {
    //對象初始化以前執行
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization"+beanName);
        return bean;
    }
    //對象初始化對象以後運行
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization"+beanName);
        return bean;
    }
}
<bean class="com.ty.bean.MyBeanPostProcessor"></bean>
    <bean id="p" class="com.ty.bean.Person" scope="prototype" init-method="init" destroy-method="mydestory">
        <property name="id" value="1001"></property>
    </bean>

8、配置文件參數化

就是把Spring配置文件中須要常常修改的字符串信息,轉移到一個更小的配置文件中,方便後期的維護

例如:數據庫鏈接

<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
    </bean>
jdbc.username=root
jdbc.password=root
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/demo
//測試
@Test
    public void test11() throws SQLException {
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        DruidDataSource dataSource = context.getBean("dataSource", DruidDataSource.class);
        System.out.println(dataSource);
        System.out.println(dataSource.getConnection());
    }
相關文章
相關標籤/搜索