靜態(tài)代理:
代理類實現(xiàn)接口蹲姐,構(gòu)造方法傳入實現(xiàn)類實例,代理類重寫接口方法人柿,加入邏輯柴墩。
public class ProxyDemo {
public static void main(String args[]){
IRequest subject = new RealSubject();
Proxy p = new Proxy(subject);
p.request();
}
}
interface IRequest{
void request();
}
class RealSubject implements IRequest{
public void request(){
System.out.println("request");
}
}
class Proxy implements IRequest{
private IRequest subject;
public Proxy(IRequest subject){
this.subject = subject;
}
public void request(){
System.out.println("proxy before");
subject.request();
System.out.println("proxy after");
}
}
代理類是在編譯時就實現(xiàn)好的。也就是說 Java 編譯完成后代理類是一個實際的 class 文件凫岖。
動態(tài)代理:
動態(tài)代理:代理類是在運行時生成的江咳。也就是說 Java 編譯完之后并沒有實際的 class 文件,而是在運行時動態(tài)生成的類字節(jié)碼哥放,并加載到JVM中歼指。動態(tài)代理類使用字節(jié)碼動態(tài)生成加載技術(shù),在運行時生成加載類甥雕。生成動態(tài)代理類的方法很多踩身,如,JDK 自帶的動態(tài)處理社露、CGLIB挟阻、Javassist 或者 ASM 庫。JDK 的動態(tài)代理使用簡單,它內(nèi)置在 JDK 中附鸽,因此不需要引入第三方 Jar 包脱拼,但相對功能比較弱。
構(gòu)造類實現(xiàn)InvocationHandler接口坷备,重寫Invoke方法熄浓,構(gòu)造方法傳入實現(xiàn)類。 相對優(yōu)點:不用重寫所有接口方法省撑。但是只能對接口實現(xiàn)玉组。
動態(tài)代理常被應(yīng)用到以下幾種情況中:
- 數(shù)據(jù)庫連接以及事務(wù)管理
- 單元測試中的動態(tài) Mock 對象
- 自定義工廠與依賴注入(DI)容器之間的適配器
- 類似 AOP 的方法攔截器
public class DynamicProxyDemo01 {
public static void main(String[] args) {
Subject realSubject = new RealSubject(); //1.創(chuàng)建委托對象
ProxyHandler handler = new ProxyHandler(realSubject); //2.創(chuàng)建調(diào)用處理器對象
Subject proxySubject = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
RealSubject.class.getInterfaces(), handler); //3.動態(tài)生成代理對象
proxySubject.request(); //4.通過代理對象調(diào)用方法
}
}
/**
* 接口
*/
interface Subject{
void request();
}
/**
* 委托類
*/
class RealSubject implements Subject{
public void request(){
System.out.println("====RealSubject Request====");
}
}
/**
* 代理類的調(diào)用處理器
*/
class ProxyHandler implements InvocationHandler {
private Subject subject;
public ProxyHandler(Subject subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("====before====");
Object result = method.invoke(subject, args);
System.out.println("====after====");
return result;
}
}
public interface IDBQuery {
String request();
}
public class DBQuery implements IDBQuery {
public DBQuery() {
try {
Thread.sleep(1000);//假設(shè)數(shù)據(jù)庫連接等耗時操作
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
@Override
public String request() {
return "request string";
}
}
public class DBQueryHandler implements InvocationHandler {
IDBQuery realQuery = null;//定義主題接口
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//如果第一次調(diào)用,生成真實主題
if(realQuery == null){
realQuery = new DBQuery();
}
//返回真實主題完成實際的操作
return realQuery.request();
}
public static IDBQuery createProxy(){
IDBQuery proxy = (IDBQuery) Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(), new Class[]{IDBQuery.class}, new DBQueryHandler()
);
return proxy;
}
@Test
public void test(){
IDBQuery idbQuery=createProxy();
System.out.println(idbQuery.request());
}
}
當(dāng)使用者調(diào)用了代理對象所代理的接口中的方法的時候丁侄,這個調(diào)用的信息會被傳遞給InvocationHandler的invoke方法。在 invoke方法的參數(shù)中可以獲取到代理對象朝巫、方法對應(yīng)的Method對象和調(diào)用的實際參數(shù)鸿摇。invoke方法的返回值被返回給使用者。這種做法實際上相 當(dāng)于對方法調(diào)用進行了攔截劈猿。
代碼一:
private static HelloService getHelloServiceProxy() {
HelloService helloService = new HelloServiceImpl();
InvocationHandler handler = new JavaDynamicProxy(helloService);
return (HelloService) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
helloService.getClass().getInterfaces(), handler);
}
代碼二:
public List getList(final List list) {
return (List) Proxy.newProxyInstance(DummyProxy.class.getClassLoader(), new Class[] { List.class },
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("add".equals(method.getName())) {
throw new UnsupportedOperationException();
}
else {
return method.invoke(list, args);
}
}
});
}
cglib:
既可以對接口拙吉,也可以對類實現(xiàn)。
http://blog.csdn.net/danchu/article/details/70238002