1. 程式人生 > 實用技巧 >微服務 · 如何解決鏈路追蹤問題

微服務 · 如何解決鏈路追蹤問題

spring七大模組

IoC、DI

控制反轉(ioc):是一種思想,建立物件的控制權,從程式程式碼轉移到了ioc容器。

依賴注入(di):是控制反轉的實現方法,bean物件的建立依賴於容器,bean物件中所有的屬性由容器注入。

IoC的實現:採用XML配置 / 使用註解

依賴注入的方式

1.構造器注入,【在配置檔案載入的時候,容器中管理的物件就已經建立了】

<!--1.下標賦值-->
<bean id="id_name" class="全類名">
    <construct-arg index="0" value="xx"/>
    <construct-arg index="1" value="xxx"/>
</bean>
<!--2.型別賦值,不推薦使用,當多個引數型別相同時 會報錯-->
<bean id="id_name" class="全類名">
    <construct-arg type="java.lang.String" value="xx"/>
</bean>
<!--3.引數名賦值-->
<bean id="id_name" class="全類名">
    <construct-arg name="name" value="xx"/>
</bean>

2.set注入,常用

<!--1.普通注入-->
<bean id="id_name" class="全類名">
    <property name="name" value="xx"/>
</bean>
<!--2.bean注入-->
<bean id="id_name" class="全類名">
    <property name="name" ref="bean_id"/>
</bean>
<!--3.陣列-->
<bean id="id_name" class="全類名">
   <property name="name">
     <array>
         <value>xx</value>
         <value>xxx</value>
     </array>
    </property>
</bean>
<!--4.list-->
<bean id="id_name" class="全類名">
   <property name="name">
     <list>
         <value>xx</value>
         <value>xxx</value>
     </list>
    </property>
</bean>
<!--5.set-->
<bean id="id_name" class="全類名">
   <property name="name">
     <set>
         <value>xx</value>
         <value>xxx</value>
     </set>
    </property>
</bean>
<!--6.map-->
<bean id="id_name" class="全類名">
   <property name="name">
     <map>
         <entry key="x" value="xx"/>
     </map>
    </property>
</bean>
<!--7.空值注入-->
<bean>
  <property>
    <null/>   
  </property>
</bean>
<!--properties-->
<bean>
  <property>
     <pros>
        <prop key="x">xx</prop>
        <prop key="xx">xxx</prop>
     </pros>   
  </property>
</bean>

3.介面注入(spring不支援)

bean的作用域

Scope Description
singleton 容器中只有一個bean的例項
prototype 每次從容器中獲取bean時,都會產生一個新的例項
request 每次http請求都會建立一個新物件
session 同一個會話共享一個例項,不同的會話使用不同的例項
global-session 所有會話共享同一個例項

singleton:單例,一個類只有一個例項。【spring預設作用域】

prototype:原型,每次從容器中獲取物件的時候都會產生一個新物件。

其餘三個只能在web開發中使用。

bean的自動裝配

xml實現在自動裝配:autowired = "byName / byType"

  • byName自動裝配:保證bean的id唯一

  • byType自動裝配:保證bean的class唯一

使用註解實現自動裝配:

  • @Autowired; 【最常用】
    • 欄位上
    • set方法上
    • 構造方法上
  • 如果@Autowired自動裝配的環境比較複雜(bean的id 不唯一,類中有多個相同的屬性),可以使用@Qulifier(value="xx")配合@Autowired,指定一個唯一的bean物件注入。
  • @Resource(name="xx");【功能更強大】

@Autowired和@Resource的區別:

  • 都是用來實現自動裝配的,都可以放在屬性上
  • @Autowired通過byType實現,如果xml中有多個相同型別的bean,就會注入失敗,報空指標異常
  • @Resource通過byName實現,如果找不到對應的bean的id,就通過byType實現!如果xml中有多個相同型別的bean,就會注入失敗,報bean不唯一異常

@Component有三個衍生註解

對應三成架構中的每一層

  1. Dao【@Repository】
  2. Service【@Service】
  3. Controller【@Controller】

這四個註解的功能都是一樣的,為當前類註冊bean物件,交給spring容器管理

三層架構和MVC的區別

AOP是一種技術

​ 提取並封裝跟核心業務無關的重複程式碼。在需要呼叫的時候,使用動態代理技術,在不修改原始碼的基礎上對方法進行增強。比如:許可權管理、事務處理、日誌記錄。

代理模式:靜態代理,動態代理

靜態代理

角色分析:

  • 抽象角色:一般使用介面或者抽象類
  • 具體角色:被代理的角色
  • 代理角色:代理真實角色,相當於中間商,代理後會做一些附屬操作
  • 客戶:訪問代理物件的人

好處:

  • 使具體角色的操作更純粹!不用再去關注一些公共的業務
  • 公共的業務交給代理角色,實現了業務的分工
  • 公共業務集中管理,需要擴充套件功能時候更加方便

缺:

  • 一個真實角色就會產生一個代理角色,程式碼量翻倍==開發效率變低

動態代理

  • 角色和靜態代理角色一樣
  • 動態代理的代理類是動態生成的,不是我們寫好的!
  • 動態代理分為兩大類:
    • 基於介面:JDK動態代理
    • 基於子類:cglib代理

需要了解兩個類:Proxy(用於生成代理類),InvocationHandler(介面,呼叫處理程式)

JDK動態代理好處:

  • 有靜態代理的所有優點
  • 一個動態代理代理的是一個介面,對應一類業務
  • 一個動態代理可以代理多個類,只要這些類實現了同一個介面

缺:

  • 只會增強最先呼叫的方法,內部之間相互呼叫的方法,是不會被增強的。【這在基於子類和基於介面的動態代理方法中都存在。】

AOP的實現方式

  1. 使用spring的API

    <?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:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop.xsd">
        <!--註冊bean-->
        <bean id="afterLog" class="proxy.AfterLog"></bean>
        <bean id="beforeLog" class="proxy.BeforeLog"></bean>
        <bean id="user2" class="proxy.User"></bean>
        <!--配置aop,需要匯入aop的約束-->
        <aop:config>
            <aop:pointcut id="pointcut"
                          expression="execution(* proxy.User.*(..))"/>
            <!--執行增強-->
            <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
            <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        </aop:config>
    </beans>
    
  2. 自定義切面(是一個類)來實現aop

    <?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:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop.xsd">
        <!--註冊bean-->
        <bean id="user2" class="proxy.User"></bean>
        <!--自定義切面-->
        <bean id="aspect" class="proxy.DiyLog"/>
        <aop:config>
            <aop:aspect ref="aspect">
        <!--切入點-->
                <aop:pointcut id="point" expression="execution(* proxy.User.*(..))"/>
        <!--通知-->
                <aop:before method="before" pointcut-ref="point"/>
                <aop:after method="after" pointcut-ref="point"/>
            </aop:aspect>
        </aop:config>
    </beans>
    
  3. 使用註解實現

    <!--    方式三,使用註解實現-->
        <bean id="annotationPointCut" class="proxy.DiyLog"/>
    <!--    開啟註解支援-->
        <aop:aspectj-autoproxy/>
    
            
    package proxy;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    //自定義切面,是一個類
    @Aspect   //表明當前類是一個切面
    public class DiyLog {
        @Before("execution(* proxy.User.*(..))")
        public void before(){
            System.out.println("======方法執行前=======");
        }
        @After("execution(* proxy.User.*(..))")
        public void after(){
            System.out.println("======方法執行後=======");
        }
    }
    

spring中的事務管理

  • 宣告式事務
  • 程式設計式事務(不使用)

配置宣告式事務

<!--配置 事務管理器-->
<bean id="dataSourceTransactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
<!--配置事務通知-->
<tx:advice id="txAdvice"
               transaction-manager="dataSourceTransactionManager">
        <!--給哪些方法配置事務-->
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
<!--配置aop-->

為什麼需要事務:

如果不配置事務,可能存在資料提交不一致的情況,涉及到資料的一致性和完整性問題。