1. 程式人生 > 其它 >Linux下的輸入輸出

Linux下的輸入輸出

技術標籤:spring框架設計模式javaaopspring

1 代理模式的產生

  • 額外功能

    1. 軟體設計者的角度Service層不需要額外功能
    2. Service層的呼叫者則需要額外功能
    
    示例:
    1. 房東(軟體設計者)出租房子,只想實現核心功能而不去實現額外功能
    	核心功能:
    		1.出租房屋
    		2.收錢
    	額外功能:
    		1.打廣告
    		2.帶客戶看方
    2. 房客(軟體呼叫者)則需要這些額外功能。
    此時房東和房客就會產生矛盾,應景而生中介(proxy)。房東不想實現的額外功能中介來實現
    

2 設計模式

2.1 概念
通過代理類,為原始類(目標類)增加額外的功能
2.2 好處
利於原始類的維護
2.3 示例場景
事務、日誌、效能檢測
2.4 核心要素
1. 原始類
2. 代理物件和原始物件實現相同的介面(代理類必須和原始類的方法保持一致,所以需要實現共同的介面)
3. 額外功能

3 靜態代理

3.1 編碼實現

在這裡插入圖片描述

3.2 存在問題
1. 每一個原始類都需要與之對應的代理類的實現,靜態類檔案數量過多,不利於專案管理
2. 額外功能難以維護,需要去修改每一個代理類的額外功能實現

4 動態代理

4.1 spring的動態代理
4.1.1 依賴jar包
org.springframework:spring-aop:5.1.14.RELEASE
org.aspectj:aspectjrt:1.8.8
org.aspectj:aspectjewaver:1.8.3
4.1.2 實現額外功能
/**
 * @author wl
 * @version 1.0
 * @Description 實現MethodBeforeAdvice介面重寫before方法,實現原始方法之前的額外功能
 * @date 2021/1/20 19:36
 */
public class Before implements MethodBeforeAdvice {

    /**
     * @Description 需要把在原始方法執行之前執行的額外功能寫在before方法中
     * @Param [method, objects, o]
     * @return
     */
@Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("--- method before advice ----"); } }
4.1.3 原始類、共同介面
// 共同介面
public interface UserService {
    
    boolean login(String name, String password);
}

// 原始類
public class UserServiceImpl implements UserService {
    @Override
    public boolean login(String name, String password) {
        return true;
    }
}
4.1.4 定義切入點
切入點:額外功能加入的位置

<!-- spring的xml配置檔案中定義切入點-->
<aop:config>
    <!-- 給所有方法加入額外功能 -->
	<aop:pointcut id="ex" expression="execution(* *(..))"
</aop:config>
4.1.5 組裝
<!-- 將切入點和額外功能整合 -->
<bean name="before" class = "Before"></bean>
<aop:config>
    <!-- 給所有方法加入額外功能 -->
	<aop:pointcut id="ex" expression="execution(* *(..))"/>
    <!-- 指定額外功能和切入點的id -->
    <aop:advisor advice-ref="before" pointcut-ref="ex"/>
</aop:config>
4.1.6 呼叫
spring的工廠通過原始物件的id值獲得的是代理物件
    <bean name="userService" class="UserServiceImpl"></bean>
    所以 getBean("userService")獲得的是代理物件。
將獲取的代理物件進行儲存,可通過共同介面的型別宣告
	UserService userService = (UserSerivce)applicationContext.getBean("userService");
4.2 spring動態代理細節
4.2.1 代理類存放位置
Spring框架在執行時,通過動態位元組碼技術,在JVM中建立的,代理類執行在JVM內部。生命週期和JVM一致
4.2.2 動態位元組碼
不存在靜態java檔案,也就無法編譯成class檔案。
動態位元組碼是通過第三方的動態位元組碼框架在JVM中建立。如:Cglib、ASM、Javassist
有了位元組碼就可在JVM中建立物件
4.2.3 動態代理好處
1. 不需要定義代理類檔案,都是JVM執行過程中動態建立。不會造成類檔案過程,而影響專案管理的問題。
2. 在額外功能不改變的情況下,只需要指定原始類,不再需要如靜態代理般自己定義代理檔案
3. 額外功能要改變的化,只需要重新實現Advice介面重新組裝,不再需要如靜態代理般每個代理都去修改
4.2.4 MethodBeforeAdivce詳解
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
	System.out.println("--- method before advice ----");
}
1. 引數
	Method method
		額外功能所增加原始類的對應原始方法
	Object[] objects 
		method原始方法的所有引數
	Object o
		原始類物件
4.2.5 MethodInterceptor方法攔截器
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class Around implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        return invocation.proceed();
    }
}
MethodBeforeAdivce和MethodInterceptor的區別:
	前者只能在方法之前新增額外功能,後者則可以在方法的前後都可新增額外功能

1. 引數
	MethodInvocation invocation
		原始方法封裝
2. 原始方法的呼叫
		invocation.proceed();
	注意:當前額外功能加在哪個原始方法上,此時的invocation.proceed()就代表執行呼叫該原始方法。
3. 額外功能
		寫在invocation.proceed()之前和之後的程式碼就是額外功能
4. 返回值
	Object
		原始方法的返回值 -- 返回值為void的Object為Null
4.2.6 Adivce原理
1. 事務的實現(around) -- 原始方法之前開始事務,之後提交事務;
2. 原始方法丟擲異常後的額外功能 -- 將額外功能寫在invocation.proceed()方法呼叫的catch塊中;
3. 無論是否有異常都執行的額外功能 -- 將額外功能寫在finall程式碼塊中.
4.3 切面詳解
4.3.1 概念
連線點:在應用執行過程中能夠插入切面的一個點
	所有的連線點就組成了整個切點
切點:定義了需要在哪些連線點上執行通知
	明確了執行在哪些方法上
切面:切點(在哪裡) + 通知(什麼時候)組成了切面。
	切面的類中定義了切點和通知
4.3.2 切入點表示式
表示式書寫原理
示例:【* *(..)】【修飾符+返回值 方法名(引數型別+引數個數)】
代表所有方法:*為萬用字元,代表無要求,引數兩個點代表引數無要求,即該表示式適配所有方法

修飾符+返回值 包 類 方法 (引數)
* com.examine.controller.Uc.login(String,com.wangl.examine.entiry.user) 

1. 方法切入點
	1.1 某個具體方法 -- 非java.lang包中型別的引數,必須寫全限定類名
		* com.wangl.examine.controller.C.login(String,com.wangl.examine.entiry.user)
	1.2 未知引數方法 -- 兩個點代表多或者沒有,型別無限制
		* com.wangl.examine.controller.UserController.login(..)
2. 類切入點
	2.1 某個具體類 -- 包含類中所有方法
		* com.wangl.examine.controller.UserController.*(..)
	2.2 忽略包
		2.2.1 類只存在一級包 -- com.UserController
			* *.UserController.*(..)
		2.2.2 類存在多級包   -- com.wangl.examine.controller.UserController
			* *..UserController.*(..)
3. 包切入點
	3.1 不包含包的子包中的資源
		* com.wangl.examine.controller.*.*(..)
	3.2 包含包及其子包資源
		* com.wangl.examine.controller..*.*(..)
4.4 JDK動態代理
1. 建立原始物件
	UserSercice userService = new UserServiceImpl();
2. JDK建立動態代理物件
	Proxy.newProxyInstance(classloader,interfaces,invocationHandler);
		返回值:Object 代表生成的動態代理物件
		  引數: 1.ClassLoader 由於動態代理物件沒有class位元組碼檔案,所以動態代理物件沒有被JVM分配類載入器。但是又必須由ClassLooader為代理物件生成Class物件,所以就需要借用其他類的類載入器。
		  	   2.interfaces 代理物件和原始物件實現的介面
		  	   3.invocationHandler 實現了InvocationHandler介面的類
3. 額外功能
	實現InvocationHandler介面,並重寫其invoke(Object proxy,Method method,Object[] args)方法
		引數:1.proxy 代表代理物件,一般忽略掉
			 2.method 額外功能所增加給的當前物件的原始方法
			 3.args 原始方法的引數
		返回值:Object 代表原始方法的返回值
4.4.1 編碼
public class ProxyHandler {

	public static void main(String[] args) {
		// 內部類使用外部類的區域性變數需要宣告為final
        final UserService userService = new UserServiceImpl();

        // 內部類
		InvocationHandler ih = new InvocationHandler() {

			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				System.out.println("------ Proxy before ----");
				// 原始方法
                Object res = method.invoke(userService, args);
				System.out.println("------ Proxy after ----");
				return res;
			}
		};
		// 生成的代理物件
		UserService proxy =
            // 借用的ClassLoader,借用其他類的也可以
            (UserService)Proxy.newProxyInstance(UserService.class.getClassLoader(),				userService.getClass().getInterfaces(), ih);
		// 動態代理物件呼叫方法
        proxy.login();
	}
}