java中動(dòng)態(tài)代理的實(shí)現(xiàn)
動(dòng)態(tài)代理的實(shí)現(xiàn)
使用的模式:代理模式。
代理模式的作用是:為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問。類似租房的中介。
兩種動(dòng)態(tài)代理:
(1)jdk動(dòng)態(tài)代理,jdk動(dòng)態(tài)代理是由Java內(nèi)部的反射機(jī)制來實(shí)現(xiàn)的,目標(biāo)類基于統(tǒng)一的接口(InvocationHandler)
(2)cglib動(dòng)態(tài)代理,cglib動(dòng)態(tài)代理底層則是借助asm來實(shí)現(xiàn)的,cglib這種第三方類庫實(shí)現(xiàn)的動(dòng)態(tài)代理應(yīng)用更加廣泛,且在效率上更有優(yōu)勢(shì)。
主要應(yīng)用的框架:
Spring中的AOP,Struts2中的攔截器
具體實(shí)現(xiàn):
1、定義接口和實(shí)現(xiàn)類
package com.example.service;
public interface UserService {
public String getName(int id);
public Integer getAge(int id);
}
package com.example.service.impl;
import com.example.service.UserService;
public class UserServiceImpl implements UserService {
public String getName(int id) {
System.out.println("------getName------");
return "cat";
}
public Integer getAge(int id) {
System.out.println("------getAge------");
return 10;
}
}
2、jdk動(dòng)態(tài)代理實(shí)現(xiàn)
package com.example.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
/**
* 綁定委托對(duì)象并返回一個(gè)代理類
*
* @param target
* @return
*/
public Object bind(Object target) {
this.target = target;
//取得代理對(duì)象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); //要綁定接口(這是一個(gè)缺陷,cglib彌補(bǔ)了這一缺陷)
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("getName".equals(method.getName())) {
System.out.println("------before " + method.getName() + "------");
Object result = method.invoke(target, args);
System.out.println("------after " + method.getName() + "------");
return result;
} else {
Object result = method.invoke(target, args);
return result;
}
}
}
package com.example.jdk;
import com.example.service.UserService;
import com.example.service.impl.UserServiceImpl;
/**
* 測(cè)試類
*/
public class RunJDK {
public static void main(String[] args) {
MyInvocationHandler proxy = new MyInvocationHandler();
UserService userServiceProxy = (UserService) proxy.bind(new UserServiceImpl());
System.out.println(userServiceProxy.getName(1));
System.out.println(userServiceProxy.getAge(1));
}
}
運(yùn)行結(jié)果:
------before getName------
------getName------
------after getName------
cat
------getAge------
10
3、cglib動(dòng)態(tài)代理實(shí)現(xiàn):
JDK的動(dòng)態(tài)代理機(jī)制只能代理實(shí)現(xiàn)了接口的類,而不能實(shí)現(xiàn)接口的類就不能實(shí)現(xiàn)JDK的動(dòng)態(tài)代理,cglib是針對(duì)類來實(shí)現(xiàn)代理的,他的原理是對(duì)指定的目標(biāo)類生成一個(gè)子類,并覆蓋其中方法實(shí)現(xiàn)增強(qiáng),但因?yàn)椴捎玫氖抢^承,所以不能對(duì)final修飾的類進(jìn)行代理。
CGLIB的核心類:
net.sf.cglib.proxy.Enhancer – 主要的增強(qiáng)類
net.sf.cglib.proxy.MethodInterceptor – 主要的方法攔截類,它是Callback接口的子接口,需要用戶實(shí)現(xiàn)
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method類的代理類,可以方便的實(shí)現(xiàn)對(duì)源對(duì)象方法的調(diào)用。
net.sf.cglib.proxy.MethodInterceptor接口是最通用的回調(diào)(callback)類型,它經(jīng)常被基于代理的AOP用來實(shí)現(xiàn)攔截(intercept)方法的調(diào)用。這個(gè)接口只定義了一個(gè)方法
public Object intercept(Object object, java.lang.reflect.Method method,
Object[] args, MethodProxy proxy) throws Throwable;
第一個(gè)參數(shù)是代理對(duì)像,第二和第三個(gè)參數(shù)分別是攔截的方法和方法的參數(shù)。原來的方法可能通過使用java.lang.reflect.Method對(duì)象的一般反射調(diào)用,或者使用 net.sf.cglib.proxy.MethodProxy對(duì)象調(diào)用。net.sf.cglib.proxy.MethodProxy通常被首選使用,因?yàn)樗臁?/p>
package com.example.cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLIBProxy implements MethodInterceptor {
private Object target;
/**
* 創(chuàng)建代理對(duì)象
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回調(diào)方法
enhancer.setCallback(this);
// 創(chuàng)建代理對(duì)象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("++++++before " + methodProxy.getSuperName() + "++++++");
System.out.println(method.getName());
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("++++++after " + methodProxy.getSuperName() + "++++++");
return result;
}
}
package com.example.cglib;
import com.example.service.UserService;
import com.example.service.impl.UserServiceImpl;
/**
* 測(cè)試CGLIB
*/
public class RunCGLIB {
public static void main(String[] args) {
CGLIBProxy cglibProxy = new CGLIBProxy();
UserService userService = (UserService) cglibProxy.getInstance(new UserServiceImpl());
userService.getName(1);
userService.getAge(1);
}
}
運(yùn)行結(jié)果:
++++++before CGLIB$getName$0++++++
getName
------getName------
++++++after CGLIB$getName$0++++++
++++++before CGLIB$getAge$1++++++
getAge
------getAge------
++++++after CGLIB$getAge$1++++++
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)后臺(tái)圖片跨域上傳功能
這篇文章主要給大家介紹了關(guān)于java實(shí)現(xiàn)后臺(tái)圖片跨域上傳功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
java遞歸設(shè)置層級(jí)菜單的實(shí)現(xiàn)
本文主要介紹了java遞歸設(shè)置層級(jí)菜單的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
java 將 list 字符串用逗號(hào)隔開拼接字符串的多種方法
這篇文章主要介紹了java 將 list 字符串用逗號(hào)隔開拼接字符串,本文給大家分享四種方法,每種方法通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12
Java的Struts框架中Action的編寫與攔截器的使用方法
這篇文章主要介紹了Java的Struts框架中Action的編寫與攔截器的使用方法,Struts框架是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-11-11
sql于navicat中能運(yùn)行在mybatis中不能運(yùn)行的解決方案
這篇文章主要介紹了sql于navicat中能運(yùn)行在mybatis中不能運(yùn)行的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
記一次springboot配置redis項(xiàng)目啟動(dòng)時(shí)的一個(gè)奇怪的錯(cuò)誤
這篇文章主要介紹了spring?boot配置redis項(xiàng)目啟動(dòng)時(shí)的一個(gè)奇怪的錯(cuò)誤,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
IDEA取消SVN關(guān)聯(lián),再重新分享項(xiàng)目的操作
這篇文章主要介紹了IDEA取消SVN關(guān)聯(lián),再重新分享項(xiàng)目的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Spring MVC @GetMapping和@PostMapping注解的使用方式
這篇文章主要介紹了Spring MVC @GetMapping和@PostMapping注解的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05

