1. 程式人生 > 實用技巧 >java-spring

java-spring

Spring-IOC

ioc概念

控制反轉

把物件建立和物件之間的呼叫過程,交給Spring 進行管理。

目的就是,為了降低耦合度,因為當你想在一個類當中呼叫另外一個類的方法,你需要獲得另外一個類的例項

IOC的底層原理:
包括xml解析,工廠模式,反射

引入工廠模式之後:

IOC解耦過程

IOC介面:

1Ioc思想基於IOC容器完成,IO容器底層就是物件工廠
2Spring提供IOC容器實習兩種方式:兩個介面

1)BeanFactory :IOC容器基本實現,Spring內部的使用介面,不提供給開發人員進行使用

2)ApplicationContext :BeanFactory介面的子介面,提供更強大的功能,一般開發人員使用


區別:
BeanFactory 載入配置檔案的時候不會建立物件,在獲取物件的時候才建立。

ApplicationContext ,載入檔案的時候,會將配置檔案裡面的物件進行建立。

獲取IOC容器的方式

通過beanFactory

通過applicationContext獲取

3 ApplicationContext介面實現類

FileSystemXmlApplicationContext從碟符路徑開始查詢配置檔案,絕對路徑

ClassPathXmlApplicationContext專案路徑下查詢-----一般使用

IOC操作Bean管理
Bean管理是什麼:

1Spring建立物件
2Spring注入屬性

Bean管理操作兩種方式

基於xml配置檔案方式實現
基於註解方式實現

JOC操作Bean管理--基於xml方式

基於xml方式建立物件

</bean>
<bean id="
usert" class="com.quan.Usert" > </bean>

1)在sprin配置檔案中,使用bean標籤,標籤理新增相應的屬性,就可以實現物件建立

2)bean標籤的屬性

id:屬性 =唯一標識

class屬性=類的全路徑

3)預設使用無參構造方法完成物件的建立

bean的作用域

單例 - 每個Spring IoC 容器返回一個bean例項 singleton
原型- 當每次請求時返回一個新的bean例項 prototype
請求 - 返回每個HTTP請求的一個Bean例項
會話 - 返回每個HTTP會話的一個bean例項
全域性會話- 返回全域性HTTP會話的一個bean例項 

預設是單例 

     ApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml");
        for (int i = 0; i < 3; i++) {
            User user = (User)ac.getBean("user");
            System.out.println(user);
        }

singleton作用域

共享一個例項bean,只建立一個例項,

結果為:

/*socpe為sigleon的時候
com.quan.User@67784306
com.quan.User@67784306
com.quan.User@67784306
 */

prototype作用域

每次注入這個類的時候,都建立一個例項

v/*socpe為prototype的時候
com.quan.User@63753b6d
com.quan.User@6b09bb57
com.quan.User@6536e911
 */

bean標籤的屬性init-method= destroy-method=

先說兩個介面先:

InitializingBean DisposableBean 標記介面 ,
主要實現Spring 執行bean時的初始化和銷燬時某些方法

實現InitializingBean ,需要實現afterPropertiesSet,就是設定所有的屬性之後做什麼
實現DisposableBean 實現destory(),就是Spring 容器釋放該bean之後做些什麼

public class InitialDisp implements InitializingBean, DisposableBean {

    public void destroy() throws Exception {
        System.out.println("destroy");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("afterProper");
    }
}

執行:

public class BETest {
    public static void main(String[] args) {
        /*
        ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable
        ApplicationContext:應用上下文
        Lifecycle:負責context的生命週期進行管理,提供start(),stop() 以及isRunning()
        Closeable:用於關閉元件,釋放資源
        ConfigurableApplicationContext 介面的作用就是設定上下文 ID,設定父應用上下文,新增監聽器,重新整理容器,關閉,判斷是否活躍等方法
         */
        ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml");
        InitialDisp id = (InitialDisp)ac.getBean("initdesp");
        System.out.println(id);
        ac.close();
    }
}
/*
re:
afterProper
com.quan.hll.InitialDisp@1f36e637
destroy
 */

但是不建議使用這兩個介面

可以指定類中的某個方法為兩個階段的方法:init-method= destroy-method=

上面的類不在繼承那兩個介面

再bean配置檔案當中:

 <bean id="initdesp" class="com.quan.hll.InitialDisp" init-method="afterPropertiesSet" destroy-method="destroy"></bean>
建議使用init-method和destroy-methodbean在Bena配置檔案,而不是執行 InitializingBean 和 DisposableBean 介面,也會造成不必要的耦合程式碼在Spring。

設定bean載入和銷燬所呼叫的方法

</bean>
<bean id="usert" class="com.quan.Usert" init-method="init" destroy-method="destroy">
</bean>

test;

      ApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml");

        Usert usert = (Usert)ac.getBean("usert");
        usert.say();
        //關閉ioc容器
        ((ClassPathXmlApplicationContext) ac).close();

基於xml方式注入屬性

1)DI: 依賴注入,就是注入屬性,是IOC的一種實現方式

依賴注入-setter方法;

11類需要各個屬性的set方法

22配置檔案中先建立物件,再注入屬性

依賴注入---構造方法

1)需要建立有參建構函式

2)配置檔案中使用constructor-arg標籤

第一個類:

View Code

第二個類:

View Code

spring-config.xml配置

<!--    建立User物件,id是這個資源的唯一表示-->
<bean id="user" scope="prototype" class="com.quan.User">
<!--    通過構造方法注入-->
    <constructor-arg index="0" value="QQgou"/>
    <constructor-arg index="1" ref="usert"/>
<!--    這裡的user例項裡面的name屬性會被下面的設定替代,如果沒有就是構造器的值-->
    <property name="name">
        <value>QQSpring</value>
    </property>
<!--  name這裡是指User類裡面的屬性usert  這裡的ref是指下面的bean-->
    <property name="usert" ref="usert">
    </property>
</bean>
<bean id="usert" class="com.quan.Usert" init-method="init" destroy-method="destroy">
</bean>

re;

init see you
how to sayQQSpring
see you

注:加顏色就是通過構造方法注入的形式,裡面還有屬性是其他類的設定

IOC操作Bean管理-xml注入其他型別屬性

字面量

null值

再熟悉值裡面不要設定value屬性,直接加入null標籤

    <bean id="user" class="com.quan.hlll.User">
        <property name="name">
            <null></null>
        </property>
    </bean>

特殊符號<<>>

進行轉義操作

    <bean id="user" class="com.quan.hlll.User">
        <property name="name" value="&lt;&gt;<<南京>>"></property>
    </bean>

把帶特殊符號內容寫到CDATA

    <property name="name">
            <value><![CDATA[<<南京>>]]></value>
        </property>

注入屬性-外部bean

person累有一個屬性為hello物件型別

     <bean id="person" class="com.quan.hll.javaConfig.Person.Person">
          <constructor-arg index="0" value="QQQ"/>
          <constructor-arg index="1" ref="hello" />
     </bean>
     <bean id="hello" class="com.quan.hll.javaConfig.Hello.Hello"></bean>

注意屬性-內部bean和級聯賦值

View Code

通過建構函式(其實set方法也是可以的)

     <bean id="person" class="com.quan.hll.javaConfig.Person.Person">
          <constructor-arg index="0" value="QQQ"/>
          <constructor-arg index="1" >
               <bean class="com.quan.hll.javaConfig.Hello.Hello"></bean>
          </constructor-arg>
     </bean>

內部定義的累有屬性的時候

注意:建議在類的內部進行內部類的定義:

 <bean id="person" class="com.quan.hll.javaConfig.Person.Person">
          <constructor-arg index="0" value="QQQ"/>
          <constructor-arg index="1" >
              <bean class="com.quan.hll.javaConfig.Hello.Hello">
                   <property name="msg">
                        <value>ourmsg</value>
                   </property>
              </bean>
          </constructor-arg>
     </bean>

bean屬性值的注入兩種xml格式

View Code

<!--     使用屬性標籤property其的下級value屬性進行值的注入,-->
     <bean id="mconstructor" class="com.quan.hll.manyConstruntor.MConstructor" >
          <property name="name" >
               <value>quan</value>
          </property>
          <property name="addr">
               <value>gd</value>
          </property>
          <property name="age">
               <value>23</value>
          </property>
     </bean>

<!--     使用快捷方式進行值的注入,-->
     <bean id="mconstructor" class="com.quan.hll.manyConstruntor.MConstructor" >
          <property name="age" value="23"/>
          <property name="addr" value="gd"/>
          <property name="name" value="q1234"/>
     </bean>

IOC操作Bean管理(xml-注入集合屬性)

格式:

<list value-type="java.lang.String">
    <value>list裡面的元素</value>
        ...
</list>

<set>
    <value>set元素</value>
            ...
</set>


<map>
    <entry key=key值 value=key值對應的value/>
    ....
</map>


<props>
    <prop key=key值>value值寫這裡</prop>
            .....
</props>

eg

<bean id="springlist" class="com.quan.hll.List.SpringList">
<!--          list-->
          <property name="lists" >
               <list value-type="java.lang.String">
                    <value>quan</value>
                    <value>quan</value>
                    <value>quan2</value>
               </list>
          </property>
<!--          set-->
          <property name="sets">
               <set>
<!--                    因為set屬性不允許重複,只保留一個-->
                    <value>quan</value>
                    <value>quan</value>
                    <value>quan2</value>
               </set>
          </property>
<!--          Map-->
          <property name="maps">
               <map>
<!--                    同樣只保留後者-->
                    <entry key="one" value="QQQ"/>
                    <entry key="one" value="ZZZ"/>
                    <entry key="two" value="ZZZ"/>
               </map>
          </property>
<!--          properties-->
          <property name="properties">
               <props>
                    <prop key="quan">shige213</prop>
                    <prop key="zhi">shige321</prop>
               </props>
          </property>
     </bean>
View Code

類:

package com.quan.hll.List;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class SpringList {
    private List<Object> lists;
    private Set<Object> sets;
    private Map<Object,Object> maps;
    private Properties  properties;

    public List<Object> getLists() {
        return lists;
    }

    public void setLists(List<Object> lists) {
        this.lists = lists;
    }

    public Set<Object> getSets() {
        return sets;
    }

    public void setSets(Set<Object> sets) {
        this.sets = sets;
    }

    public Map<Object, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<Object, Object> maps) {
        this.maps = maps;
    }

    public Properties getProperties() {
        return properties;
    }

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

列印類:

[quan, quan, quan2]
{one=ZZZ, two=ZZZ}
{quan=shige213, zhi=shige321}
[quan, quan2]

spring注入日期:

     <bean id="sdate" class="com.quan.hll.List.Sdate">
<!--          使用下面會報錯,必須使用格式話進行格式話-->
<!--          <property name="date" value="2020-12-20"/>-->
<!--          Cannot convert value of type [java.lang.String] to required type -->
<!--          [java.util.Date] for property 'date': no matching edit-->
               <property name="date">
                    <bean factory-bean="dataFormat" factory-method="parse">
                         <constructor-arg value="2020-12-20"></constructor-arg>
                    </bean>
               </property>
     </bean>

     <bean id="dataFormat" class="java.text.SimpleDateFormat">
          <constructor-arg value="yyyy-MM-dd"/>
     </bean>

re:Sdate{date=Sun Dec 20 00:00:00 CST 2020}

PropertyPlaceholderConfigurer對映

用於配置檔案的管理,

datasource.properties

driver=com.jdbc.mysql.connection
url=jdbc:mysql:localhost:3306
username=root
password=2009

<!--     載入PropertyPlaceholderConfigurerbean,並指定檔案位置-->
     <bean  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
          <property name="location">
               <value>datasource.properties</value>
          </property>
     </bean>

     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
         <property name="driverClassName" value="${driver}"/>
         <property name="username" value="${username}"/>
         <property name="password" value="${password}"/>
         <property name="url" value="${url}"/>
     </bean>

spring-bean的繼承

這裡不是在java下建立類去extend而是通過bean的配置檔案去實現

主要是bean父設定一個模板或者屬性,子bean公用這個屬性或者模板

類:

public class BasePlace  {
    private String place;
    private String name;

下面父bean只是共享自己的name的屬性值

    <bean id="base" class="com.quan.hll.expand.BasePlace" >
        <property name="name" value="Q"/>
    </bean>

    <bean id="expandbase" parent="base">
        <property name="place" value="sz"/>

    </bean>

注意:其實expandbase這個bean也是com.quan.hll.expand.BasePlace類

加入下面的這個bean標籤的屬性是說明父bean不可被例項化:

 <bean id="base" class="com.quan.hll.expand.BasePlace" abstract="true">

如果呼叫:
BasePlace bb = (BasePlace)ac.getBean("base");

報錯

加入下面一句,子類bean新設定的屬性值會覆蓋父bean

 <property name="name" value="QQ"/>

BasePlace{place='sz', name='Q'}

@Required註解依賴檢查,指定類中的屬性檢查,部分!!!

單單加入這個還是不生效,需要在bean.xml檔案裡面引入解析註解的bean

適用於bean屬性setter方法,並表示受影響的bean屬性必須在XML配置檔案在配置時進行填充。否則,容器會丟擲一個BeanInitializationException異常。

public class BasePlace  {
    private String place;
    private String name;


    @Required
    public void setName(String name) {
        this.name = name;
    }

bean。xml

    <bean id="base" class="com.quan.hll.expand.BasePlace" >
        <property name="place" value="ShenZhen"/>
    </bean>

baocuo

org.springframework.beans.factory.BeanInitializationException:
 Property 'name' is required for bean 'base'

註冊一個RequiredAnnotationBeanPostProcessor以瞭解在bean配置檔案@Required註解

111

設定context:

<context:annotation-config/>

22設定bean

<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>

自定義@required註解名字(換名字)

編寫註解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyRequired {
}

註冊註解:

<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor">
    <property name="requiredAnnotationType" value="com.quan.hll.MyRequired"></property>
</bean>

使用即可:

public class BasePlace  {
    private String place;
    private String name;


    @MyRequired
    public void setName(String name) {
        this.name = name;
    }

使用javaConfig(註解)代替spring-config.xml來配置bean

/*
通過java類來載入bean,註解
 */

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class HelloConfig {
    @Bean(name = "hello")
    public Hello hello(){
        return new Hello();
    }
}

相當於:

 <bean id="hello" class="com.quan.hll.javaConfig.Hello" ></bean>

        //通過JavaConfig的類物件來獲取ApplicationConext
//        ApplicationContext ac = new AnnotationConfigApplicationContext(HelloConfig.class);
        //通過spring-config.xml配置檔案來進行bean載入
        ApplicationContext ac =  new ClassPathXmlApplicationContext("spring-config.xml");

多個bean模組化設定配置檔案

多個建構函式的歧義

package com.quan.hll.manyConstruntor;

public class MConstructor{
    private  String name;
    private int age;
    private String addr;

    /*
    兩個建構函式,可能會出現起義
     */
    public MConstructor(int age, String name,  String addr) {
        this.name = name;
        this.age = age;
        this.addr = addr;
    }

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


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

/*
第一次沒有指定型別出現這個結果:
MConstructor{name='23', age=199, addr='123'}
 */

<!--     兩個建構函式,可能會出現起義-->
<!--     <bean id="mconstructor" class="com.quan.hll.manyConstruntor.MConstructor" >-->
<!--          <constructor-arg >-->
<!--               <value>199</value>-->
<!--          </constructor-arg>-->
<!--          <constructor-arg>-->
<!--               <value>23</value>-->
<!--          </constructor-arg>-->
<!--          <constructor-arg>-->
<!--               <value>123</value>-->
<!--          </constructor-arg>-->
<!--     </bean>-->

<!--     為建構函式指定的確切資料型別,-->
     <bean id="mconstructor" class="com.quan.hll.manyConstruntor.MConstructor" >
          <constructor-arg type="java.lang.String" >
               <value>199</value>
          </constructor-arg>
          <constructor-arg type="int">
               <value>23</value>
          </constructor-arg>
          <constructor-arg type="java.lang.String">
               <value>123</value>
          </constructor-arg>
     </bean>

多個配置檔案歸結到一個配置檔案

     <import resource="hello-config.xml"/>
     <import resource="person-config.xml"/>


SpEL(Spring Expression Language),