日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
面試官:講講SpringAOP的底層代理模式

代理模式相信大家經(jīng)常聽(tīng)說(shuō),在設(shè)計(jì)模式中相對(duì)而言是比較難理解的。這次指北君來(lái)給大家通俗的介紹介紹。

1.什么是代理模式

Provide a surrogate or placeholder for another object to control access to it.

Proxy Pattern:為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)。

說(shuō)人話:在不改變?cè)碱?或叫被代理類)代碼的情況下,通過(guò)引入代理類來(lái)給原始類附加功能,比如Spring AOP。

2.代理模式定義

①Subject

抽象主題角色,可以是抽象類,可以是接口,是一個(gè)最普通的業(yè)務(wù)類定義,無(wú)特殊要求。

②RealSubject

真實(shí)主題角色,也叫被代理角色,是業(yè)務(wù)邏輯的具體執(zhí)行者。

③Proxy

代理主題角色,也叫代理類,它負(fù)責(zé)對(duì)真實(shí)角色的應(yīng)用,把所有抽象主題類定義的方法限制委托給真實(shí)主題角色實(shí)現(xiàn),并在真實(shí)主題角色處理前后做一些預(yù)處理或善后工作。

通用代碼如下:

/**
* 抽象主題類
*/
public interface Subject {
void doSomething();
}
/**
* 真實(shí)主題角色
*/
public class RealSubject implements Subject{

@Override
public void doSomething() {
//TODO 具體執(zhí)行的事
}
}
/**
* 代理主題角色
*/
public class Proxy implements Subject{
//要代理的具體實(shí)現(xiàn)類
private Subject realSubject;

public Proxy(Subject realSubject){
this.realSubject = realSubject;
}
@Override
public void doSomething() {
this.before();
realSubject.doSomething();
this.after();
}

// 預(yù)處理
private void before(){
// TODO
}

// 善后處理
private void after(){
// TODO
}
}

3.代理模式的兩種實(shí)現(xiàn)

比如用代理模式實(shí)現(xiàn)統(tǒng)計(jì)某個(gè)接口的耗時(shí)。

3.1 靜態(tài)代理

①基于接口編程

抽象主題類:

public interface IUserController {
// 登錄
String login(String username,String password);
// 注冊(cè)
String register(String username,String password);
}

具體主題類:

public class UserController implements IUserController{
@Override
public String login(String username, String password) {
// TODO 登錄邏輯
return null;
}

@Override
public String register(String username, String password) {
// TODO 注冊(cè)邏輯
return null;
}
}

代理主題類:

public class UserControllerProxy implements IUserController{
private IUserController userController;

public UserControllerProxy(IUserController userController){
this.userController = userController;
}
@Override
public String login(String username, String password) {
long startTime = System.currentTimeMillis();
// 登錄邏輯
userController.login("username","password");
long endTime = System.currentTimeMillis();
long responseTime = endTime - startTime;
System.out.println("接口響應(yīng)時(shí)間:"+responseTime);
return null;
}

@Override
public String register(String username, String password) {
long startTime = System.currentTimeMillis();
// 注冊(cè)邏輯
userController.register("username","password");
long endTime = System.currentTimeMillis();
long responseTime = endTime - startTime;
System.out.println("接口響應(yīng)時(shí)間:"+responseTime);
return null;
}
}

測(cè)試:

因?yàn)樵碱?UserController 和代理類 UserControllerProxy 實(shí)現(xiàn)相同的接口,是基于接口而非實(shí)現(xiàn)編程,將UserController類對(duì)象替換為UserControllerProxy類對(duì)象,不需要改動(dòng)太多代碼

public class StaticProxyTest {
public static void main(String[] args) {
IUserController userController = new UserControllerProxy(new UserController());
userController.login("username","password");
userController.register("username","password");
}
}

在上面的代碼中,代理類和具體主題類需要實(shí)現(xiàn)相同的接口,假如具體主題類沒(méi)有實(shí)現(xiàn)接口,并且不是我們開(kāi)發(fā)維護(hù)的(比如來(lái)自第三方接口),我們要統(tǒng)計(jì)這個(gè)第三方接口的耗時(shí),那應(yīng)該如何實(shí)現(xiàn)代理模式呢?

②基于繼承

繼承具體主題類,然后擴(kuò)展其方法即可,直接看代碼。

public class UserControllerProxy extends UserController {
@Override
public String login(String username, String password) {
long startTime = System.currentTimeMillis();
// 登錄邏輯
super.login("username","password");
long endTime = System.currentTimeMillis();
long responseTime = endTime - startTime;
System.out.println("接口響應(yīng)時(shí)間:"+responseTime);
return null;
}

@Override
public String register(String username, String password) {
long startTime = System.currentTimeMillis();
// 注冊(cè)邏輯
super.register("username","password");
long endTime = System.currentTimeMillis();
long responseTime = endTime - startTime;
System.out.println("接口響應(yīng)時(shí)間:"+responseTime);
return null;
}
}

3.2 動(dòng)態(tài)代理

在上面的例子中,有兩個(gè)問(wèn)題:

①我們需要在代理類中,將具體主題類中的所有的方法,都重新實(shí)現(xiàn)一遍,并且為每個(gè)方法都附加相似的代碼邏輯,如果方法很多,重復(fù)代碼也會(huì)很多。

②如果要添加的附加功能的類有不止一個(gè),我們需要針對(duì)每個(gè)類都創(chuàng)建一個(gè)代理類。

那該如何解決上面的問(wèn)題呢?答案就是動(dòng)態(tài)代理(Dynamic Proxy)。

動(dòng)態(tài)代理:不事先為每個(gè)原始類編寫代理類,而是在運(yùn)行的時(shí)候,動(dòng)態(tài)地創(chuàng)建原始類對(duì)應(yīng)的代理類,然后在系統(tǒng)中用代理類替換掉原始類。

JDK動(dòng)態(tài)代理:

public class DynamicProxyHandler implements InvocationHandler {

private Object target;
public DynamicProxyHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = method.invoke(this.target, args);
long endTime = System.currentTimeMillis();
long responseTime = endTime - startTime;
System.out.println("接口響應(yīng)時(shí)間:"+responseTime);
return result;
}
}

測(cè)試:

public class DynamicProxyTest {
public static void main(String[] args) {
// 1、創(chuàng)建具體主題類
IUserController userController = new UserController();
// 2、創(chuàng)建 Handler
DynamicProxyHandler proxyHandler = new DynamicProxyHandler(userController);
// 3、動(dòng)態(tài)產(chǎn)生代理類
IUserController o = (IUserController)Proxy.newProxyInstance(userController.getClass().getClassLoader(),
userController.getClass().getInterfaces(),
proxyHandler);
o.login("username","password");
o.register("username","password");
}
}

這是 JDK 動(dòng)態(tài)代理,利用反射機(jī)制生成一個(gè)實(shí)現(xiàn)代理接口的匿名類,在調(diào)用具體方法前調(diào)用InvokeHandler來(lái)處理,代理對(duì)象是在程序運(yùn)行時(shí)產(chǎn)生的,而不是編譯期,要求是具體主題類必須實(shí)現(xiàn)接口。

另外一種方式是 Cglib 動(dòng)態(tài)代理。CGLIB(Code Generation Library)是一個(gè)基于ASM的字節(jié)碼生成庫(kù),它允許我們?cè)谶\(yùn)行時(shí)對(duì)字節(jié)碼進(jìn)行修改和動(dòng)態(tài)生成,也就是通過(guò)修改字節(jié)碼生成子類來(lái)處理。

Cglib 動(dòng)態(tài)代理:

public class UserController{
public String login(String username, String password) {
// TODO 登錄邏輯
System.out.println("登錄");
return null;
}

public String register(String username, String password) {
// TODO 注冊(cè)邏輯
System.out.println("注冊(cè)");
return null;
}
}

注意:真實(shí)主題類是沒(méi)有實(shí)現(xiàn)接口的。

public class CglibDynamicProxy implements MethodInterceptor {
private Object target;

public CglibDynamicProxy(Object target){
this.target = target;
}

// 給目標(biāo)創(chuàng)建代理對(duì)象
public Object newProxyInstance(){
// 1.工具類
Enhancer enhancer = new Enhancer();
// 2.設(shè)置父類
enhancer.setSuperclass(target.getClass());
// 3.設(shè)置回調(diào)函數(shù)
enhancer.setCallback(this);
// 4.創(chuàng)建子類(代理對(duì)象)
return enhancer.create();
}

@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = method.invoke(this.target, args);
long endTime = System.currentTimeMillis();
long responseTime = endTime - startTime;
System.out.println("接口響應(yīng)時(shí)間:"+responseTime);
return result;
}
}

測(cè)試:

public class CglibDynamicProxyTest {
public static void main(String[] args) {
UserController userController = new UserController();
CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy(userController);
UserController o = (UserController)cglibDynamicProxy.newProxyInstance();
o.login("username","password");
o.register("username","password");
}
}

4.代理模式優(yōu)點(diǎn)

①職責(zé)清晰

真實(shí)的角色就是實(shí)現(xiàn)實(shí)際的業(yè)務(wù)邏輯, 不用關(guān)心其他非本職責(zé)的事務(wù), 通過(guò)后期的代理完成一件事務(wù), 附帶的結(jié)果就是編程簡(jiǎn)潔清晰。

②高擴(kuò)展性

具體主題角色是隨時(shí)都會(huì)發(fā)生變化的, 只要它實(shí)現(xiàn)了接口, 甭管它如何變化,代理類完全都可以在不做任何修改的情況下使用。

5.代理模式應(yīng)用場(chǎng)景

①業(yè)務(wù)系統(tǒng)的非功能性需求開(kāi)發(fā)

這是最常用的一個(gè)場(chǎng)景。比如:監(jiān)控、統(tǒng)計(jì)、鑒權(quán)、限流、事務(wù)、冪等、日志。我們將這些附加功能與業(yè)務(wù)功能解耦,放到代理類中統(tǒng)一處理,讓程序員只需要關(guān)注業(yè)務(wù)方面的開(kāi)發(fā)。

典型例子就是 SpringAOP。

②RPC

RPC(遠(yuǎn)程代理) 框架也可以看作一種代理模式,通過(guò)遠(yuǎn)程代理,將網(wǎng)絡(luò)通信、數(shù)據(jù)編解碼等細(xì)節(jié)隱藏起來(lái)??蛻舳嗽谑褂?RPC 服務(wù)的時(shí)候,就像使用本地函數(shù)一樣,無(wú)需了解跟服務(wù)器交互的細(xì)節(jié)。除此之外,RPC 服務(wù)的開(kāi)發(fā)者也只需要開(kāi)發(fā)業(yè)務(wù)邏輯,就像開(kāi)發(fā)本地使用的函數(shù)一樣,不需要關(guān)注跟客戶端的交互細(xì)節(jié)。


網(wǎng)頁(yè)題目:面試官:講講SpringAOP的底層代理模式
本文鏈接:http://m.5511xx.com/article/ccsoihj.html