jdk动态代理与cglib动态代理例子
1.JAVA的動(dòng)態(tài)代理特征:特征是代理類(lèi)與委托類(lèi)有同樣的接口,代理類(lèi)主要負(fù)責(zé)為委托類(lèi)預(yù)處理消息、過(guò)濾消息、把消息轉(zhuǎn)發(fā)給委托類(lèi),以及事后處理消息等。代理類(lèi)與委托類(lèi)之間通常會(huì)存在關(guān)聯(lián)關(guān)系,一個(gè)代理類(lèi)的對(duì)象與一個(gè)委托類(lèi)的對(duì)象關(guān)聯(lián),代理類(lèi)的對(duì)象本身并不真正實(shí)現(xiàn)服務(wù),而是通過(guò)調(diào)用委托類(lèi)的對(duì)象的相關(guān)方法,來(lái)提供特定的服務(wù)。
它是在運(yùn)行是生成的class對(duì)象,在生成時(shí)必須提供一組或一個(gè)interface給它,然后該class就宣稱(chēng)它實(shí)現(xiàn)了這些interface。你當(dāng)然可以把該class的實(shí)例當(dāng)做這些interface中的任何一個(gè)來(lái)用,當(dāng)然,這個(gè)DynamicProxy其實(shí)就是一個(gè)Proxy,他不會(huì)替你做實(shí)質(zhì)性的工作,在生成它的實(shí)例時(shí)你必須提供一個(gè)handler,由它接管實(shí)際的工作。因此,DynamicProxy必須實(shí)現(xiàn)InvocationHandler接口。
5) 一個(gè)動(dòng)態(tài)代理了和一個(gè)InvocationHandler 實(shí)現(xiàn)關(guān)聯(lián)的。每一個(gè)動(dòng)態(tài)代理實(shí)例的調(diào)用都要通過(guò)InvocationHandler接口的handler(調(diào)用處理器)來(lái)調(diào)用,動(dòng)態(tài)代理不做任何執(zhí)行操作,只是在創(chuàng)建動(dòng)態(tài)代理時(shí),把要實(shí)現(xiàn)的接口和handler關(guān)聯(lián),動(dòng)態(tài)代理要幫助被代理執(zhí)行的任務(wù),要轉(zhuǎn)交給handler來(lái)執(zhí)行。其實(shí)就是調(diào)用invoke方法
動(dòng)態(tài)代理:在程序運(yùn)行時(shí),運(yùn)用反射機(jī)制動(dòng)態(tài)創(chuàng)建而成
2.實(shí)用動(dòng)態(tài)代理步驟:
A. 創(chuàng)建一個(gè)實(shí)現(xiàn)接口InvocationHandler的類(lèi),他必須實(shí)現(xiàn)invoke方法
B. 創(chuàng)建被代理的類(lèi)以及接口。
C. 通過(guò)Proxy的靜態(tài)方法newProxyInstance(ClassLoader loader,Class【】interfaces,InvocationHandler handler)創(chuàng)建一個(gè)代理
D. 通過(guò)代理調(diào)用方法
?
3.jdk動(dòng)態(tài)代理例子:
文件列表:
業(yè)務(wù)接口:UserService
業(yè)務(wù)實(shí)現(xiàn):UserServiceImpl
代理類(lèi)的調(diào)用Handler實(shí)現(xiàn):ProxyHandler
JUnit測(cè)試類(lèi):SpringProxyTest
package com.niewj.service;
import com.niewj.model.User;
public class UserServiceImpl implements UserService {
?@Override
?public void add(User user) {
??System.out.println("User Saved. & ");
?}
?@Override
?public void delete(User user) {
??System.out.println("User Deleted. &");
?}
}
?
package com.niewj.service;
import com.niewj.model.User;
public class UserServiceImpl implements UserService {
?@Override
?public void add(User user) {
??System.out.println("User Saved. & ");
?}
?@Override
?public void delete(User user) {
??System.out.println("User Deleted. &");
?}
}
?
package com.niewj.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
?* JDK動(dòng)態(tài)代理模擬
?*
?* 1.首先明確什么是目標(biāo)對(duì)象target,什么是代理對(duì)象proxy!!
?*
?* 2.每個(gè)代理對(duì)象對(duì)象都會(huì)有一個(gè)相關(guān)的InvocationHandler對(duì)象。
?* 當(dāng)代理對(duì)象生成的時(shí)候,是創(chuàng)建的代理對(duì)象,
?* 拿著相關(guān)的這個(gè)InvocationHandler對(duì)象,去自動(dòng)調(diào)Handler類(lèi)中實(shí)現(xiàn)的invoke方法的。
?* 下面一段話(huà)來(lái)自@javadoc@
?* <p>Each proxy instance has an associated invocation handler.
?* When a method is invoked on a proxy instance, the method
?* invocation is encoded and dispatched to the <code>invoke</code>
?* method of its invocation handler.
?*
?* 3.還有就是我發(fā)現(xiàn),我的Eclipse控制臺(tái)TMD輸出的順序有誤,害的老以為我人品出了什么問(wèn)題,
?* 不知道控制臺(tái)的信息是不是不是棧式輸出的。(好繞口)
?*
?*/
public class ProxyHandler implements InvocationHandler {
?// 就是要給這個(gè)目標(biāo)類(lèi)創(chuàng)建代理對(duì)象。
?private Object target;
?// 傳遞代理目標(biāo)的實(shí)例,因?yàn)榇硖幚砥餍枰R部梢杂胹et等方法。
?public ProxyHandler(Object target) {
??this.target = target;
?}
?/*
? * 這個(gè)方法是給代理對(duì)象調(diào)用的。
? * 留心的是內(nèi)部的method調(diào)用的對(duì)象是目標(biāo)對(duì)象,可別寫(xiě)錯(cuò)。
? */
?@Override
?public Object invoke(Object proxy, Method method, Object[] args)
???throws Throwable {
??Object ret = null;
??// 1.調(diào)用前
??cutIntoBefore(method.getName());
??ret = method.invoke(target, args);
??// 2.調(diào)用后
??cutIntoAfter(method.getName());
??return ret;
?}
?public void cutIntoBefore(String mName) {
??System.err.println("調(diào)用____" + mName + "()____方法之前");
?}
?public void cutIntoAfter(String mName) {
??System.err.println("調(diào)用____" + mName + "()____方法完后");
?}
}
?
package com.niewj;
import java.lang.reflect.Proxy;
import org.junit.Test;
import com.niewj.model.User;
import com.niewj.service.ProxyHandler;
import com.niewj.service.UserService;
import com.niewj.service.UserServiceImpl;
public class SpringProxyTest {
?@Test
?@SuppressWarnings("rawtypes")
?public void testJDKDynamicProxy() {
??/* 1.獲取UserServiceImpl對(duì)象--目標(biāo)對(duì)象--也就是需要被代理的對(duì)象。 */
??UserService userService = new UserServiceImpl();
??// 獲取當(dāng)前類(lèi)名
??Class clazz = userService.getClass();
??/*
?? * 2.獲得代理對(duì)象。
?? * 每一個(gè)代理對(duì)象都有一個(gè)相關(guān)的InvocationHandler對(duì)象,通過(guò)這個(gè)handler對(duì)象的invoke來(lái)實(shí)現(xiàn)調(diào)用中要完成的自定義貓膩行為
?? * 。 可以使用Proxy類(lèi)和自定義的調(diào)用處理邏輯來(lái)生成一個(gè)代理對(duì)象的。
?? */
??UserService userServiceProxy = (UserService) Proxy.newProxyInstance(
????clazz.getClassLoader(), clazz.getInterfaces(),
????new ProxyHandler(userService));
??userServiceProxy.add(new User("dotjar"));
??userServiceProxy.delete(new User("DDD"));
?}
}
?
4.cglib動(dòng)態(tài)代理
JDK實(shí)現(xiàn)動(dòng)態(tài)代理需要實(shí)現(xiàn)類(lèi)通過(guò)接口定義業(yè)務(wù)方法,對(duì)于沒(méi)有接口的類(lèi),如何實(shí)現(xiàn)動(dòng)態(tài)代理呢,這就需要CGLib了。CGLib采用了非常底層的字節(jié)碼技術(shù),其原理是通過(guò)字節(jié)碼技術(shù)為一個(gè)類(lèi)創(chuàng)建子類(lèi),并在子類(lèi)中采用方法攔截的技術(shù)攔截所有父類(lèi)方法的調(diào)用,順勢(shì)織入橫切邏輯。JDK動(dòng)態(tài)代理與CGLib動(dòng)態(tài)代理均是實(shí)現(xiàn)Spring AOP的基礎(chǔ)。
它的運(yùn)行速度要遠(yuǎn)遠(yuǎn)快于JDK的Proxy動(dòng)態(tài)代理。
?
使用CGLIB需要導(dǎo)入以下兩個(gè)jar文件:
?
??? asm.jar – CGLIB的底層實(shí)現(xiàn)。
?
??? cglib.jar – CGLIB的核心jar包。
?
例子:
package com.niewj.service;
import java.lang.reflect.Method;
import com.niewj.model.User;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CgLibProxyImitation implements MethodInterceptor {
?private Enhancer enhancer = new Enhancer();
?/** 創(chuàng)建代理對(duì)象
? * @param targetClass
? * @return 返回代理對(duì)象
? */
?@SuppressWarnings("rawtypes")
?public Object getProxy(Class targetClass) {
??enhancer.setSuperclass(targetClass); //設(shè)置需要?jiǎng)?chuàng)建子類(lèi)的類(lèi)
??enhancer.setCallback(this);
??return enhancer.create(); //通過(guò)字節(jié)碼技術(shù)動(dòng)態(tài)創(chuàng)建子類(lèi)實(shí)例
?}
?public void cutIntoBefore(String mName) {
??System.err.println("調(diào)用____" + mName + "()____方法之前");
?}
?public void cutIntoAfter(String mName) {
??System.err.println("調(diào)用____" + mName + "()____方法完后");
?}
?/*? 生成的代理對(duì)象調(diào)用此對(duì)象來(lái)替代原始對(duì)象
? *
? * @java.lang.Object 增強(qiáng)對(duì)象
? * @java.lang.reflect.Method 攔截方法
? * @java.lang.Object[] 參數(shù)數(shù)組
? * @net.sf.cglib.proxy.MethodProxy? 用于調(diào)用父類(lèi),按需要調(diào)用多次
? */
?@Override
?public Object intercept(Object obj, Method method, Object[] args,
???MethodProxy proxy) throws Throwable {
??cutIntoBefore(method.getName());
??Object result = proxy.invokeSuper(obj, args);
??cutIntoAfter(method.getName());
??return result;
?}
?
?public static void main(String[] args) {
//??UserService userService = new UserServiceImpl();
??CgLibProxyImitation cglib = new CgLibProxyImitation();
??UserServiceImpl userService = (UserServiceImpl)cglib.getProxy(UserServiceImpl.class);
??userService.add(new User("dotjar"));
??userService.delete(new User("hill"));
?}
}
?
總結(jié)
以上是生活随笔為你收集整理的jdk动态代理与cglib动态代理例子的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SQLPlus 在连接时通常有四种方式
- 下一篇: ubuntu 12.10 php55安