最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java動(dòng)態(tài)代理靜態(tài)代理實(shí)例分析

 更新時(shí)間:2020年03月16日 13:18:58   作者:譚寶貴  
這篇文章主要介紹了Java動(dòng)態(tài)代理靜態(tài)代理實(shí)例分析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

代理模式:為其他對(duì)象提供一種代理以控制某個(gè)對(duì)象的訪問(wèn)。用在:在某些情況下,一個(gè)客戶不想或者不能直接訪問(wèn)另一個(gè)對(duì)象,而代理對(duì)象可以在客戶端和目標(biāo)對(duì)象之前起到中介的作用,代理對(duì)象還可以完成它附加的操作。

例子:就像房東、租客、中介的關(guān)系。中介(代理對(duì)象)為房東(真實(shí)對(duì)象)出租房子,租客(客戶)通過(guò)中介(代理對(duì)象)來(lái)找房子租房子,中介完成了租房以后可以收取中介費(fèi)(附加操作)。

先看看靜態(tài)代理模式,通過(guò)上面對(duì)代理模式的理解,可以了解到代理模式:即不直接通過(guò)new一個(gè)真實(shí)對(duì)象來(lái)調(diào)用方法,而是通過(guò)代理對(duì)象來(lái)調(diào)用一個(gè)方法,所以代理對(duì)象包含真實(shí)對(duì)象的引用。下面看一下代碼

接口:Subject包含一個(gè)方法

 package com.example.designpattern.proxy; 
 public interface Subject {
 void request();
 }

RealSubject類,實(shí)現(xiàn)了Subject接口,為了簡(jiǎn)單起見(jiàn),方法簡(jiǎn)單的輸出一句話:

package com.example.designpattern.proxy;
public class RealSubject implements Subject {
//真是角色實(shí)現(xiàn)了
public void request() {
System.out.println("From real subject");
}
}

代理類ProxySubject,也要實(shí)現(xiàn)Subject接口,實(shí)現(xiàn)Subject里面的方法,但是在這里里面是通過(guò)調(diào)用真實(shí)對(duì)象來(lái)實(shí)現(xiàn)的。

package com.example.designpattern.proxy;

public class ProxySubject implements Subject {

private RealSubject realSubject; //代理角色內(nèi)部引用了真實(shí)角色

//代理角色實(shí)現(xiàn)目標(biāo)動(dòng)作
public void request() {

this.preRequest(); //在真實(shí)角色操作之前所附加的操作
if (realSubject == null){
realSubject = new RealSubject();
}
realSubject.request(); // 真實(shí)角色所完成的事情
this.afterRequet(); //在真實(shí)角色操作之后附加的操作
}
//代理角色之前完成的動(dòng)作
private void preRequest(){
System.out.println("pre request");
}
//代理角色之后完成的動(dòng)作
private void afterRequet(){
System.out.println("after request");
}
}

客戶調(diào)用者

package com.example.designpattern.proxy;

public class Client {
public static void main(String[] args) {
ProxySubject proxy = new ProxySubject();
//通過(guò)代理對(duì)象來(lái)調(diào)用方法
proxy.request(); 
}
}

靜態(tài)代理:

可以運(yùn)行一下這些代碼哦, 可以在Client類中看到,是通過(guò)代理ProxySubject的對(duì)象proxy來(lái)調(diào)用方法的,在代理類ProxySubject中,有一個(gè)真實(shí)對(duì)象的引用,在代理對(duì)象的中request()方法調(diào)用了真實(shí)對(duì)象的方法。這樣的模式叫做代理模式。

優(yōu)點(diǎn)是:

1. 代理模式能將代理對(duì)象與真實(shí)對(duì)象被調(diào)用的目標(biāo)對(duì)象分離。

2. 一定程度上降低了系統(tǒng)的耦合度,擴(kuò)展性好。

代理類中包含了對(duì)真實(shí)主題的引用,這樣做也有缺點(diǎn):

1. 真實(shí)對(duì)象與代理類一一對(duì)應(yīng),增加真實(shí)類也要增加代理類,這樣做會(huì)快速的增加類的數(shù)量,使得系統(tǒng)變得復(fù)雜。

2. 設(shè)計(jì)代理以前真實(shí)主題必須事先存在,不太靈活。

采用動(dòng)態(tài)代理可以解決以上問(wèn)題,動(dòng)態(tài)代理是相對(duì)于靜態(tài)代理來(lái)說(shuō)的。

可能你也會(huì)說(shuō)怎么樣實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建實(shí)例,以前我們創(chuàng)建實(shí)例不都是通過(guò)new 的方式來(lái)實(shí)現(xiàn)的嗎?

Hello hi = new Hello();

那么動(dòng)態(tài)創(chuàng)建實(shí)例是由Java提供的功能,就不需要我們?nèi)ew 對(duì)象,他已經(jīng)定義好了靜態(tài)方法Proxy.newProxyInstance(),只要傳入?yún)?shù)調(diào)用就可以。Java文檔里面有哦,如圖:

Java標(biāo)準(zhǔn)庫(kù)提供了一種動(dòng)態(tài)代理(DynamicProxy)的機(jī)制:可以在運(yùn)行期動(dòng)態(tài)創(chuàng)建某個(gè)interface的實(shí)例。

參數(shù)解釋:

 Proxy.newProxyInstance(
 ClassLoader loader, // 傳入ClassLoader
 Class<?>[] interfaces, // 傳入要調(diào)用的接口的方法數(shù)組
 InvocationHandler h); //傳入InvocationHandler 的實(shí)例

下面看一下動(dòng)態(tài)代理例子代碼:

Subject 接口

package design.dynamicproxy;
public interface Subject {
void request(String str);
}

RealSubject類 實(shí)現(xiàn) Subject 接口

package design.dynamicproxy;
public class RealSubject implements Subject {
@Override
public void request(String str) {
System.out.println("From Real Subject!" + " args:" + str );
}
}

動(dòng)態(tài)代理類DynamicSubject 實(shí)現(xiàn)了InvocationHandler,重寫(xiě)invoke()方法

package design.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
* 該代理類的內(nèi)部屬性時(shí)Object類型,實(shí)際使用時(shí),使用該類的構(gòu)造方法傳遞一個(gè)對(duì)象
* 此外該類還實(shí)現(xiàn)了invoke() 方法,該方法中的method.invoke() 其實(shí)就是要調(diào)用被代理對(duì)象的要執(zhí)行的方法
* 方法參數(shù)是object,表示該方法從屬于object對(duì)象,通過(guò)動(dòng)態(tài)代理類,我們可以在執(zhí)行真是對(duì)象的
* 方法前后可以加入一些額外的方法
*/
public class DynamicSubject implements InvocationHandler {

//引入的類型是Object的,可以隨便傳入任何一個(gè)對(duì)象
private Object object;

public DynamicSubject(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling:" + method);
//等價(jià)于realSubject的request() 方法,如果這里不調(diào)用的話,不會(huì)調(diào)用Method 對(duì)象中的方法
method.invoke(object, args);
System.out.println("after calling:" + method);
return null;
}
}

Client類

package design.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client {
	public static void main(String[] args) {
		RealSubject realSubject = new RealSubject();
		InvocationHandler handler = new DynamicSubject(realSubject);
		Class<?> classType = handler.getClass();
		//下面的代碼一次性生成代理
		// 動(dòng)態(tài)生成了class com.sun.proxy.$Proxy0 的實(shí)例,
		Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(),handler);
		subject.request("eather");
		System.out.println(subject.getClass());
		//輸出class com.sun.proxy.$Proxy0,可以看到Proxy.newProxyInstance() 是系統(tǒng)自動(dòng)生成的實(shí)例
	}
}

在Client中可以看到,我們這里調(diào)用方法的是 subject.request("eather"); 這個(gè)對(duì)象subject 不是通過(guò)new DynamicSubject()生成的,而是Java內(nèi)部寫(xiě)好的方法在運(yùn)行時(shí)動(dòng)態(tài)生成對(duì)象;可能有人說(shuō)

InvocationHandler handler = new DynamicSubject(realSubject);

這里不是通過(guò)new new DynamicSubject(realSubject); 生成了一個(gè)對(duì)象嗎? 是的,但是它是InvocationHandler 類型的,主要是傳遞一個(gè)InvocationHandler類型參數(shù)給Proxy.newProxyInstance(); 即最后一個(gè)參數(shù)。通過(guò)Client類的最后一句輸出可以看到它是 class com.sun.proxy.$Proxy0 ,這是Java運(yùn)行時(shí)生成的。

解決了靜態(tài)代理的難題:1. 真實(shí)對(duì)象與代理類一一對(duì)應(yīng),增加真實(shí)類也要增加代理類,這樣做會(huì)快速的增加類的數(shù)量,使得系統(tǒng)變得復(fù)雜。 為什么這么說(shuō)呢, 因?yàn)榇眍愐玫念愋褪荗bject的,可以隨便傳入任何一個(gè)對(duì)象,當(dāng)真實(shí)類增加時(shí),代理類不用增加,new DynamicSubject(object); new的時(shí)候把要傳入的對(duì)象傳進(jìn)去即可。

下面是Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h); 這個(gè)方法的源碼啦,可以看看,深入了解一下

public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
	Objects.requireNonNull(h);
	final Class<?>[] intfs = interfaces.clone();
	final SecurityManager sm = System.getSecurityManager();
	if (sm != null) {
		checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
	}
	/*
* Look up or generate the designated proxy class.
生成一個(gè)代理類對(duì)象
*/
	Class<?> cl = getProxyClass0(loader, intfs);
	/*
* Invoke its constructor with the designated invocation handler.
使用指定的調(diào)用處理程序調(diào)用其構(gòu)造函數(shù)。就是使用InvocationHandler 實(shí)例調(diào)用【要調(diào)用方法的那個(gè)類】的構(gòu)造方法
*/
	try {
		if (sm != null) {
			checkNewProxyPermission(Reflection.getCallerClass(), cl);
		}
		final Constructor<?> cons = cl.getConstructor(constructorParams);
		final InvocationHandler ih = h;
		if (!Modifier.isPublic(cl.getModifiers())) {
			AccessController.doPrivileged(new PrivilegedAction<Void>() {
				public Void run() {
					cons.setAccessible(true);
					return null;
				}
			}
			);
		}
		return cons.newInstance(new Object[]{
			h
		}
		);
	}
	catch (IllegalAccessException|InstantiationException e) {
		throw new InternalError(e.toString(), e);
	}
	catch (InvocationTargetException e) {
		Throwable t = e.getCause();
		if (t instanceof RuntimeException) {
			throw (RuntimeException) t;
		} else {
			throw new InternalError(t.toString(), t);
		}
	}
	catch (NoSuchMethodException e) {
		throw new InternalError(e.toString(), e);
	}
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • springboot項(xiàng)目如何設(shè)置時(shí)區(qū)

    springboot項(xiàng)目如何設(shè)置時(shí)區(qū)

    這篇文章主要介紹了springboot項(xiàng)目如何設(shè)置時(shí)區(qū)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • SpringCloud持久層框架MyBatis Plus的使用與原理解析

    SpringCloud持久層框架MyBatis Plus的使用與原理解析

    MyBatisPlus為MyBatis的增強(qiáng)版,專注于簡(jiǎn)化數(shù)據(jù)庫(kù)操作,提供自動(dòng)化CRUD、內(nèi)置分頁(yè)和樂(lè)觀鎖等功能,極大提升開(kāi)發(fā)效率,在SpringCloud微服務(wù)架構(gòu)中,MyBatisPlus通過(guò)插件機(jī)制和自動(dòng)生成代碼功能,有效支持企業(yè)級(jí)應(yīng)用和分布式系統(tǒng)的開(kāi)發(fā)
    2024-10-10
  • Java持久層面試題目及答案整理

    Java持久層面試題目及答案整理

    在本篇文章里小編給大家分享的是一篇關(guān)于Java持久層面試題目及答案整理內(nèi)容,需要的朋友們學(xué)習(xí)參考下。
    2020-02-02
  • mybatis批量更新與插入方式

    mybatis批量更新與插入方式

    這篇文章主要介紹了mybatis批量更新與插入方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • spring?boot?使用?@Scheduled?注解和?TaskScheduler?接口實(shí)現(xiàn)定時(shí)任務(wù)

    spring?boot?使用?@Scheduled?注解和?TaskScheduler?接口實(shí)現(xiàn)定時(shí)任務(wù)

    這篇文章主要介紹了spring?boot?使用?@Scheduled?注解和?TaskScheduler?接口實(shí)現(xiàn)定時(shí)任務(wù),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • 使用Spring的AbstractRoutingDataSource實(shí)現(xiàn)多數(shù)據(jù)源切換示例

    使用Spring的AbstractRoutingDataSource實(shí)現(xiàn)多數(shù)據(jù)源切換示例

    這篇文章主要介紹了使用Spring的AbstractRoutingDataSource實(shí)現(xiàn)多數(shù)據(jù)源切換示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • Java中PrintWriter使用方法介紹

    Java中PrintWriter使用方法介紹

    這篇文章主要介紹了Java中PrintWriter使用方法介紹,文章圍繞主題展開(kāi)PrintWriter使用方法的詳細(xì)介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-06-06
  • Java線程池submit阻塞獲取結(jié)果的實(shí)現(xiàn)原理詳解

    Java線程池submit阻塞獲取結(jié)果的實(shí)現(xiàn)原理詳解

    Java線程池中提交任務(wù)運(yùn)行,通常使用execute()方法就足夠了。那如果想要實(shí)現(xiàn)在主線程中阻塞獲取線程池任務(wù)運(yùn)行的結(jié)果,該怎么辦呢?本文就來(lái)和大家一起討論討論
    2022-10-10
  • java數(shù)據(jù)結(jié)構(gòu)之希爾排序

    java數(shù)據(jù)結(jié)構(gòu)之希爾排序

    這篇文章主要為大家詳細(xì)介紹了java數(shù)據(jù)結(jié)構(gòu)之希爾排序的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • java中jdbcTemplate的queryForList(坑)

    java中jdbcTemplate的queryForList(坑)

    本文主要介紹了java中jdbcTemplate的queryForList,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評(píng)論

汾西县| 汾西县| 吉安县| 胶南市| 浦江县| 沭阳县| 宜良县| 沭阳县| 中宁县| 衡阳县| 临江市| 崇左市| 鄂托克前旗| 七台河市| 云龙县| 沅江市| 门源| 濮阳市| 林州市| 台江县| 台南市| 榆中县| 阳朔县| 千阳县| 无锡市| 丰县| 公主岭市| 浪卡子县| 宁德市| 稷山县| 疏附县| 瑞丽市| 安吉县| 张家口市| 鸡东县| 云浮市| 邯郸市| 册亨县| 怀宁县| 阜平县| 巴林左旗|