DI、IOC基礎學習筆記

洛小白發表於2019-04-01

spring 優點

  • 方便解耦,簡化開發(高內聚低耦合)
    • Spring就是一個大廠(容器),可以將所有物件建立和依賴關係維護,交給Spring管理
  • AOP程式設計的支援
    • Spring提供面向切面程式設計,可以方便的實現對程式進行許可權攔截、執行監控等功能
  • 宣告式事務的支援
    • 只需要通過配置基於可以完成對事務的管理,而無需手動程式設計
  • 方面程式的測試
    • spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如Struts、Hibernate、MyBatis、Quartz等)的直接支援
  • 降低JavaEEAPI的使用難度
    • spring對JAVAEE開發中非常難用的一些API(JDBC,JavaMail,遠端呼叫等),都提供了封裝,使這些API應用難度大大降低

案例入門 IOC

  1. 匯入jar包

    1. 4+1:四個核心(beans、core、context、expression)+1個依賴(commons-loggins..jar)
  2. 目標類

    1. 提供UserService介面和實現

    2. 獲得UserService實現類的例項

    3. 之前開發,直接new一個物件即可,學習spring之後,將由Spring建立物件例項-->IOC控制反轉(Inverse of Control)之後需要例項物件時,從spring工廠(容器)中獲得,需要將實現類的全限定名稱配置到xml檔案中

      ``

      public interface UserService {
          public void addUser();
      }
      
      public class UserServiceImpl implements UserService{
      
          @Override
          public void addUser() {
              System.out.println("Hello world");
          }
      }
      
      複製程式碼
    @Test
    public void test(){
        //從spring容器獲得
        //1獲得容器
        String xmlPath = "com/adolph/ioc/applicationContext.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        //2獲得內容--不需要自己new,都是從spring容器中獲得
        UserService userService = (UserService) applicationContext.getBean("userServiceId");
        userService.addUser();
    
    }
    複製程式碼
  3. 配置檔案

    1. 位置:任意,開發中一般在classpath下
    2. 名稱:任意,開發中常用applicationContext.xml
    3. 內容:新增schema約束

    ``

    <?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">
    
        <!--配置server
            <bean>配置需要建立的物件
                id:用於之後從spring容器獲得例項時使用的
                class:需要建立例項的全限定類名
        -->
        <bean id="userServiceId" class="com.adolph.ioc.UserServiceImpl"></bean>
    </beans>
    複製程式碼

案例入門 DI

  • DI(Dependency Injection)依賴注入

    • is a:是一個,繼承

    • has a:有一個,成員變數,依賴

      class B{

      private A a; //B類依賴A

      }

      依賴:一個物件需要使用另一個物件

      注入:通過setter方法進行另一個物件的例項設定

      例如:

      class BookService{
    
      	//之前開發(service和dao耦合)
    
      	private BookDao bookDao = new BookDaoImpl();
    
      	//spring之後(解耦:service實現類使用dao介面,不知道具體的實現類)
    
      	private BookDao bookDao;
    
      }
    複製程式碼

模擬spring執行過程

建立service例項:BookServlice bookService = new BookService() -->IOC

建立dao例項:BookDao bookDao = new BookDaoImpl() -->IOC

將dao設定給service:bookService.setBookDao(bookDao) -->DI

目標類

建立BookService介面和實現類

建立BookDao介面和實現

將dao和service配置xml檔案

``

<!--<property>用於進行屬性名注入
name:bean的屬性名,通過setter方法獲得setBookDao
 ref:另一個bean的id值的引用##-->
<!--建立service執行過程-->
<bean id="bookServiceId" class="com.adolph.di.BookServiceImpl">
    <property name="bookDao" ref="bookDaoId"></property>
</bean>

<bean id="bookDaoId" class="com.adolph.di.BookDaoImpl"></bean>
複製程式碼

核心 API

  • BeanFactory:這是一個工廠,用於生成任意bean。採用延時載入,第一次getBean時才會初始化Bean
  • ApplicationContext:是BeanFactory的子介面,功能更強大
    • 國際化處理
    • 事件傳遞
    • Bean自動裝配
    • 各種不同應用層Context的實現
  • CalssPathXmlApplicationContext用於載入classpath(類路徑、src)下指定的xml
  • FileSystemXmlApplicationCotext 用於載入指定碟符下的xml

基於XML

1、例項化方式

3種備案例項化方式:預設構造、靜態工廠、例項工廠

  1. 預設構造

    1. 必須提供預設構造
  2. 靜態工廠

    1. 常用於與spring整合其他框架(工具)

    2. 靜態工廠:用於生成例項物件,所有的方法必須是static

    3. 例項工廠

      1. 必須先有工廠例項物件,通過例項物件建立物件。提供所有的方法都是“非靜態“的。

      ``

      public class MyBeanFactory {
          /**
           * 建立例項
           * @return
           */
          public  UserService createService(){
              return new UserServiceImpl();
          }
      }
      複製程式碼

      ``

       <!--建立工廠例項-->
      <bean id="myBeanFactory" class="com.adolph.inject.b_static_factory.MyBeanFactory"></bean>
      
       <!--獲得userService
      	factory-bean 確定工廠例項
      	factory-method 確定普通方法
      -->
       <bean id="userService" factory-bean="myBeanFactory" factory-method="createService"></bean>
      複製程式碼

2、Bean種類

  • 普通bean:之前操作的都是普通bean。,spring直接建立A例項,並返回
  • FactoryBean:是一個特殊的bean具有工廠生成物件的能力,只能生成特定的物件。bean必須使用Factory介面,此介面提供方法getObject()方法用於獲得特定bean先建立FB例項,使用呼叫getObject()方法,並返回方法的返回值。FB fb = new FB(); return fb.getObject();
  • BeanFactory和FactoryBean對比
    • BeanFactory:工廠,用於生產任意的bean
    • FactoryBean:特定bean,用於生成另一個特定的bean。 例如:ProxyFactoryBean,此工廠bean用於生產代理。獲得代理物件例項。AOP的使用

3、作用域

作用域:用於確定spring建立bean例項個數
類別 說明
singleton 在spring Ioc容器中僅存在一個Bean例項,Bean亦單例方式存在,預設值
prototype 每次從容器中呼叫Bean時,都返回一個新的例項,即每次呼叫getBean()時,相當於執行new XXBean()
request 每次HTTP請求都會建立一個新的Bean。該作用域僅適用於WebApplicationContext環境
session 同一個HTTP Session 共享一個Bean,不同Session使用不同的Bean,僅適用於WebApplicationContext環境
globalSession 一般用於Portlet應用環境,該作用域僅適用於WebApplicationContext環境
  • 取值

    • singleton 單例,預設值。
    • prototype 多例,每執行一次getBean將獲得一個例項。例如:struts整合spring,配置action多例
  • 配置資訊

<bean id="userService" class="com.adolph.inject.b_static_factory.UserServiceImpl" scope="prototype"></bean>
複製程式碼

4、生命週期

4.1、初始化和銷燬
  • 目標方法執行或執行後,將進行初始化或銷燬

    <bean id="" class="" init-method="初始化方法名稱" destroy-method="銷燬的方法名稱">
    複製程式碼

    例項

            public void myInit(){
                System.out.println("初始化");
            }

            public void myDestroy(){
                System.out.println("銷燬");
            }
        }
複製程式碼

        //要求:1,容器必須close,銷燬方法執行,2、必須是單例的
        //此方法介面中沒有定義,實現類提供
        classPathXmlApplicationContext.close();
複製程式碼
    <!--
        init-method:用於配置初始化方法,準備資料
        destroy-method:用於配置銷燬方法,清理資源
    -->
    <bean id="userServiceId" class="com.adolph.ioc.UserServiceImpl" init-method="myInit" destroy-method="myDestroy"></bean>
複製程式碼
4.2、BeanPostProcessor 後處理Bean
  • spring 提供一種機制、只要實現介面BeanPostProcessor,並將實現類提供給spring容器,spring容器將自動執行,在初始化方法前執行before(),在初始化方法後執行after() 。配置

  • spring提供工廠勾子,用於修改例項物件,可以生成代理物件,是AOP底層。

    模擬:

    //將a的例項物件傳遞給後處理bean,可以生成代理物件並放回 
    A a = new A();
    a = B.before(a);
    a.init();
    a = B.after(a)   //生成代理物件,目的在目標方法前後執行(例如:開啟事務,提交事務)
    a.addUser();
    a.destroy();
    
    
    
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("前方法" + beanName);
            return null;
        }
    
        @Override
        public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
            System.out.println("後方法" + beanName);
            return Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(),
                    bean.getClass().getInterfaces(),
                    new InvocationHandler(){
    
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("------開啟事務");
    //                        執行目標方法
                            Object obj = method.invoke(bean, args);
    
                            System.out.println("------提交事務");
                            return obj;
                        }
                    });
        }
    
    
    }
    複製程式碼
<bean class="com.adolph.ioc.MyBeanPostProcessor"></bean>
複製程式碼

4.3、setter方法

``

<bean id="person" class="com.adolph.stter.Person">
    <property name="pname" value="jack"></property>
    <property name="age">
        <value>18</value>
    </property>
    <property name="address" ref="address"></property>
</bean>

<bean  id="address" class="com.adolph.stter.Address">
    <property name="addr" value="湖南"></property>
    <property name="tel"    value="177*****43"></property>
</bean>
複製程式碼
4.4P名稱空間

,預設:xmlns=""

顯示:xmlns:別名=""

DI、IOC基礎學習筆記

4.5、SqEL
  • 對進行統一編碼,所有內容都是使用value
  • #{123}、#{'jack'}:數字、字串
  • #{beanId}:另一個bean引用
  • #{beanId.propName}:運算元據
  • #{beanId.toString}:執行方法
  • #{T(類).欄位|方法}:靜態方法或欄位
4.6、集合注入
public class CollData {

    private String[] arrrayData;

    private List<String> listData;

    private Set<String> setData;

    private Map<String,String> mapData;

    private Properties properties;

    public String[] getArrrayData() {
        return arrrayData;
    }

    public void setArrrayData(String[] arrrayData) {
        this.arrrayData = arrrayData;
    }

    public List<String> getListData() {
        return listData;
    }

    public void setListData(List<String> listData) {
        this.listData = listData;
    }

    public Set<String> getSetData() {
        return setData;
    }

    public void setSetData(Set<String> setData) {
        this.setData = setData;
    }

    public Map<String, String> getMapData() {
        return mapData;
    }

    public void setMapData(Map<String, String> mapData) {
        this.mapData = mapData;
    }

    public Properties getProperties() {
        return properties;
    }

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

    @Override
    public String toString() {
        return "CollData{" +
                "arrrayData=" + Arrays.toString(arrrayData) +
                ", listData=" + listData +
                ", setData=" + setData +
                ", mapData=" + mapData +
                ", properties=" + properties +
                '}';
    }
}

複製程式碼
  <!--
        集合的注入都是給<property>新增子標籤
        陣列:<array>
        List:<list>
        Set:<set>
        Map:<map>
        Properties:<props>

        普通資料:<value>
        引用資料:<ref>
    -->
    <bean id="collData" class="com.adolph.coll.CollData">
        <property name="arrrayData">
            <array>
                <value>1</value>
                <value>2</value>
                <value>3</value>
                <value>4</value>
            </array>
        </property>
        <property name="listData">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
                <value>4</value>
            </list>
        </property>
        <property name="setData">
            <set>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </set>
        </property>
        <property name="mapData">
            <map>
                <entry key="1" value="a"></entry>
                <entry key="2" value="b"></entry>
                <entry key="3" value="c"></entry>
            </map>
        </property>
        <property name="properties">
                <props>
                    <prop key="高富帥"></prop>
                    <prop key="白富美"></prop>
                    <prop key="屌絲"></prop>
                </props>
        </property>

    </bean>
複製程式碼

基於註釋

  • 註解:就是一個類,使用@註解名稱
  • 開發中:使用註解 取代xml配置檔案。
  1. @Component("id")取代

  2. wen開發,提供3個@Component註解衍生註解(功能一樣)

    1. @Repository:dao層
    2. @Service:service層
    3. @Controller:web層
  3. 依賴注入,可以給私有欄位設定,也可以給setter方法設定

    1. 普通值:@Value("")
    2. 引用值:
      1. 方式1:按照【型別】注入
        1. @Autowired
      2. 方式2:按照【名稱】注入1
        1. @Autowired
        2. @Qualifier("名稱")注入
      3. 方式3:按照【名稱】注入2
        1. @Resource(“名稱”)
    • @Test
       public void test() {
           String xmlPath = "com/adolph/web/beans.xml";
           ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
           StudentAction studentAction = applicationContext.getBean("studentActionId", StudentAction.class);
           studentAction.execute();
       }
      
      
      Controller("studentActionId")
      public class StudentAction {
      
          @Autowired
          private StudentService studentService;
      
          public void execute(){
              studentService.add();
          }
      }
      
      @Service
      public class StudentServiceImpl implements StudentService {
      
      
          private StudentDao studentDao;
      
          @Autowired
          @Qualifier("studentDaoId")
          public void setStudentDao(StudentDao studentDao) {
              this.studentDao = studentDao;
          }
      
          @Override
          public void add() {
              studentDao.add();
          }
      }
      
      @Repository("studentDaoId")
      public class StudentDaoImpl implements StudentDao{
          @Override
          public void add() {
              System.out.println("dao");
          }
      }
      
      
      複製程式碼

      生命週期

      ​ 初始化:@PostConstruct

      ​ 銷燬:@PreDestroy

      作用域:

      ​ @Scope("prototype") 多例

  4. 註解使用前提,新增名稱空間,讓spring掃描含有註解類**

      <!--元件掃描-->
     <context:component-scan base-package="com.adolph.annotation"></context:component-scan>
    複製程式碼

相關文章