java中動態(tài)代理的實現(xiàn)
動態(tài)代理的實現(xiàn)
使用的模式:代理模式。
代理模式的作用是:為其他對象提供一種代理以控制對這個對象的訪問。類似租房的中介。
兩種動態(tài)代理:
(1)jdk動態(tài)代理,jdk動態(tài)代理是由Java內(nèi)部的反射機制來實現(xiàn)的,目標類基于統(tǒng)一的接口(InvocationHandler)
(2)cglib動態(tài)代理,cglib動態(tài)代理底層則是借助asm來實現(xiàn)的,cglib這種第三方類庫實現(xiàn)的動態(tài)代理應用更加廣泛,且在效率上更有優(yōu)勢。
主要應用的框架:
Spring中的AOP,Struts2中的攔截器
具體實現(xiàn):
1、定義接口和實現(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動態(tài)代理實現(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;
/**
* 綁定委托對象并返回一個代理類
*
* @param target
* @return
*/
public Object bind(Object target) {
this.target = target;
//取得代理對象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); //要綁定接口(這是一個缺陷,cglib彌補了這一缺陷)
}
@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;
/**
* 測試類
*/
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));
}
}
運行結(jié)果:
------before getName------
------getName------
------after getName------
cat
------getAge------
10
3、cglib動態(tài)代理實現(xiàn):
JDK的動態(tài)代理機制只能代理實現(xiàn)了接口的類,而不能實現(xiàn)接口的類就不能實現(xiàn)JDK的動態(tài)代理,cglib是針對類來實現(xiàn)代理的,他的原理是對指定的目標類生成一個子類,并覆蓋其中方法實現(xiàn)增強,但因為采用的是繼承,所以不能對final修飾的類進行代理。
CGLIB的核心類:
net.sf.cglib.proxy.Enhancer – 主要的增強類
net.sf.cglib.proxy.MethodInterceptor – 主要的方法攔截類,它是Callback接口的子接口,需要用戶實現(xiàn)
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method類的代理類,可以方便的實現(xiàn)對源對象方法的調(diào)用。
net.sf.cglib.proxy.MethodInterceptor接口是最通用的回調(diào)(callback)類型,它經(jīng)常被基于代理的AOP用來實現(xiàn)攔截(intercept)方法的調(diào)用。這個接口只定義了一個方法
public Object intercept(Object object, java.lang.reflect.Method method,
Object[] args, MethodProxy proxy) throws Throwable;
第一個參數(shù)是代理對像,第二和第三個參數(shù)分別是攔截的方法和方法的參數(shù)。原來的方法可能通過使用java.lang.reflect.Method對象的一般反射調(diào)用,或者使用 net.sf.cglib.proxy.MethodProxy對象調(diào)用。net.sf.cglib.proxy.MethodProxy通常被首選使用,因為它更快。
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)建代理對象
*
* @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)建代理對象
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;
/**
* 測試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);
}
}
運行結(jié)果:
++++++before CGLIB$getName$0++++++
getName
------getName------
++++++after CGLIB$getName$0++++++
++++++before CGLIB$getAge$1++++++
getAge
------getAge------
++++++after CGLIB$getAge$1++++++
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!
相關(guān)文章
java 將 list 字符串用逗號隔開拼接字符串的多種方法
這篇文章主要介紹了java 將 list 字符串用逗號隔開拼接字符串,本文給大家分享四種方法,每種方法通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-12-12
Java的Struts框架中Action的編寫與攔截器的使用方法
這篇文章主要介紹了Java的Struts框架中Action的編寫與攔截器的使用方法,Struts框架是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-11-11
sql于navicat中能運行在mybatis中不能運行的解決方案
這篇文章主要介紹了sql于navicat中能運行在mybatis中不能運行的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01
記一次springboot配置redis項目啟動時的一個奇怪的錯誤
這篇文章主要介紹了spring?boot配置redis項目啟動時的一個奇怪的錯誤,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02
IDEA取消SVN關(guān)聯(lián),再重新分享項目的操作
這篇文章主要介紹了IDEA取消SVN關(guān)聯(lián),再重新分享項目的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Spring MVC @GetMapping和@PostMapping注解的使用方式
這篇文章主要介紹了Spring MVC @GetMapping和@PostMapping注解的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05

