⑴ java代理的作用和實現
JDK 動態代理
動態代理的核心其實就是代理對象的生成,即 Proxy.newProxyInstance(classLoader, proxyInterface, handler)。
讓我們進入newProxyInstance方法觀摩下,核心代碼其實就三行。
這個方法需要三個參數:
ClassLoader,用於載入代理類的 Loader 類,通常這個 Loader 和被代理的類是同一個 Loader 類。
Interfaces,是要被代理的那些那些介面。
InvocationHandler,就是用於執行除了被代理介面中方法之外的用戶自定義的操作,也是用戶需要代理的最終目的。用戶調用目標方法都被代理到 InvocationHandler 類中定義的唯一方法 invoke 中。
一個典型的動態代理創建對象過程可分為以下四個步驟:
1、通過實現InvocationHandler介面創建調用處理器
2、通過為Proxy類指定ClassLoader對象和一組interface創建動態代理類
3、通過反射機制獲取動態代理類的構造函數,其參數類型是調用處理器介面類型
4、通過構造函數創建代理類實例,此時需將調用處理器對象作為參數被傳入
為了簡化對象創建過程,Proxy類中的newProxyInstance方法封裝了2~4,只需兩步即可完成代理對象的創建。
生成的proxySubject繼承Proxy類實現Subject介面。實現的Subject的方法實際是調用處理器的invoke方法,而invoke方法利用反射調用的是被代理對象的方法(Object result=method.invoke(proxied,args));
重點Proxy.newProxyInstance,源碼分析,會在其他文檔中單獨總結記錄。類Proxy的getProxyClass方法調用ProxyGenerator的 generateProxyClass方法產生ProxySubject.class的二進制數據。
創建代理對象時序圖
獲取代理類
getProxyClass(loader, interfaces)方法用於獲取代理類,它主要做了三件事情:
在當前類載入器的緩存里搜索是否有代理類,沒有則生成代理類並緩存在本地JVM里。
生成並載入代理類
代理類的生成主要是以下這兩行代碼:
代理類的生成過程
ProxyGenerator.generateProxyClass()方法屬於sun.misc包下,Oracle並沒有提供源代碼,但是我們可以使用
JD-GUI這樣的反編譯軟體打開jrelib
t.jar來一探究竟,以下是其核心代碼的分析。
生成的代理類源碼
那麼通過以上分析,我們可以推出動態代理為我們生成了一個這樣的代理類。把方法doSomeThing的方法體修改為調用LogInvocationHandler的invoke方法。
測試代理的代碼如下:
下面看一個自定義代理的實現。
被代理類介面
被代理類
調用處理器(切面)
測試我們的代理實現
運行結果:
Proxy 介面
Proxy 的主要靜態變數
ProxySubject 源碼
創建的代理類 ProxySubject.class
CGLib 動態代理
動態位元組碼生成。使用動態位元組碼生成技術實現AOP原理是在運行期間目標位元組碼載入後,生成目標類的子類,將切面邏輯加入到子類中,所以使用Cglib實現AOP不需要基於介面。
⑵ Java代理的三種模式有什麼
Java的三種代理模式簡述
本文著重講述三種代理模式在java代碼中如何寫出,為保證文章的針對性,暫且不討論底層實現原理,具體的原理將在下一篇文章中講述。
代理模式是什麼
代理模式是一種設計模式,簡單說即是在不改變源碼的情況下,實現對目標對象的功能擴展。
比如有個歌手對象叫Singer,這個對象有一個唱歌方法叫sing()。
假如你希望,通過你的某種方式生產出來的歌手對象,在唱歌前後還要想觀眾問好和答謝,也即對目標對象Singer的sing方法進行功能擴展。
但是往往你又不能直接對源代碼進行修改,可能是你希望原來的對象還保持原來的樣子,又或許你提供的只是一個可插拔的插件,甚至你有可能都不知道你要對哪個目標對象進行擴展。這時就需要用到java的代理模式了。網上好多用生活中的經理人的例子來解釋「代理」,看似通俗易懂,但我覺得不適合程序員去理解。程序員應該從代碼的本質入手。
⑶ JAVA動態代理設計原理及如何實現
Java動態代理機制的出現,使得Java開發人員不用手工編寫代理類,只要簡單地制定一組介面及委託類對象,便能動態地獲得代理類。代理類會負責將所有的方法調用分配到委託對象上反射執行,配置執行過程中,開發人員還可以進行修改
代理設計模式
代理是一種常用的設計模式,其目的就是為其他對象提供一個代理以控制對某個對象的訪問。代理類負責為委託類預處理消息、過濾消息並轉發消息,以及進行消息被委託類執行後的後續處理。
為了保持行為的一致性,代理類和委託類通常會實現相同的介面
2. 引入代理能夠控制對委託對象的直接訪問,可以很好的隱藏和保護委託對象,也更加具有靈活性
代理機制及其特點
首先讓我們來了解一下如何使用 Java 動態代理。具體有如下四步驟:
通過實現 InvocationHandler 介面創建自己的調用處理器;
通過為 Proxy 類指定 ClassLoader 對象和一組 interface 來創建動態代理類;
通過反射機制獲得動態代理類的構造函數,其唯一參數類型是調用處理器介面類型;
通過構造函數創建動態代理類實例,構造時調用處理器對象作為參數被傳入。
代理類實例的一些特點
每個實例都會關聯一個InvocationHandler(調用處理器對象),在代理類實例上調用其代理介面中聲明的方法時,最終都會由InvocationHandler的invoke方法執行;
java.lang.Object中有三個方法也同樣會被分派到調用處理器的 invoke 方法執行,它們是 hashCode,equals 和 toString;
代碼示例
最後以一個簡單的動態代理例子結束
⑷ java動態代理怎樣實現
在目前的Java開發包中包含了對動態代理的支持,但是其實現只支持對介面的的實現。
其實現主要通過是java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler介面。
Proxy類主要用來獲取動態代理對象,InvocationHandler介面用來約束調用者實現,如下,HelloWorld介面定義的業務方法,HelloWorldImpl是HelloWorld介面的實現,HelloWorldHandler是InvocationHandler介面實現。代碼如下:
業務介面:
public interface HelloWorld {
void sayHelloWorld() ;
}
業務介面實現:
public class HelloWorldImpl implements HelloWorld {
public void sayHelloWorld() {
System.out.println("Hello World!");
}
}
InvocationHandler實現,需要在介面方法調用前後加入一部份處理工作,這里僅僅在方法調用前後向後台輸出兩句字元串,其代碼如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class HelloWorldHandler implements InvocationHandler {
//要代理的原始對象
private Object objOriginal;
/**
* 構造函數。
* @param obj 要代理的原始對象。
*/
public HelloWorldHandler(Object obj) {
this.objOriginal = obj ;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result ;
//方法調用之前
doBefore();
//調用原始對象的方法
result = method.invoke(this.objOriginal ,args);
//方法調用之後
doAfter();
return result ;
}
private void doBefore() {
System.out.println("before method invoke!");
}
private void doAfter() {
System.out.println("after method invoke!");
}
}
測試代碼:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
HelloWorld hw = new HelloWorldImpl();
InvocationHandler handler = new HelloWorldHandler(hw);
HelloWorld proxy = (HelloWorld) Proxy.newProxyInstance(
hw.getClass().getClassLoader(),
hw.getClass().getInterfaces(),
handler);
proxy.sayHelloWorld();
}
}
�0�1 首先獲取一個業務介面的實現對象;
�0�1 獲取一個InvocationHandler實現,此處是HelloWorldHandler對象;
�0�1 創建動態代理對象;
�0�1 通過動態代理對象調用sayHelloWorld()方法,此時會在原始對象HelloWorldImpl. sayHelloWorld()方法前後輸出兩句字元串。
運行測試類輸出如下:
before method invoke!
Hello World!
after method invoke!
此處Test類中的方法調用代碼比較多,在我們的實際應用中可以通過配置文件來來簡化客戶端的調用實現。另外也可以通過動態代理來實現簡單的AOP
⑸ java動態代理實現步驟
您好,提問者:
1、可以使用apache開發的HttpClient.jar來實現。
2、如果純Java代碼,首先創建一個Proxy類來進行指定協議,比如:Proxy.HTTP,構造方法請見JDK API文檔,另外指定一個SocketAddress的ip和埠,一般http埠為80。
接下來就是訪問Http網站了,使用URL url = new URL("xxx");地址,然後使用HttpConnection對象,把Proxy指定進去就可以了。
⑹ Java靜態代理和iOS代理模式這兩個概念的理解上的疑惑
java靜態代理模式,舉例給你,看下如何理解:
public class Ts {
public static void main(String[] args) throws Exception {
// 通過中介公司生產一批衣服
ClothingProct cp = new ProxCompany( new LiNingCompany());
cp.proctClothing();
}
}
/**
* 定義生產一批衣服功能的介面
*
*/
interface ClothingProct {
void proctClothing(); // 有生產一批衣服的功能
}
/**
*
* 代理類:中介公司
*
*/
class ProxCompany implements ClothingProct {
private ClothingProct cp ; // 中介公司不會生產衣服,需要找一家真正能生產衣服的公司
ProxCompany(ClothingProct cp) {
super ();
this . cp = cp;
}
@Override
public void proctClothing() {
System. out .println( "收取1塊錢的中介費" );
cp .proctClothing();
}
}
/**
*
* 李寧公司是生產服裝的目標類
*
*/
class LiNingCompany implements ClothingProct {
@Override
public void proctClothing() {
System. out .println( "生產一批衣服。。。。" );
}
}
上面程序的做法,使用的模式是靜態代理模式
靜態代理模式在現實編程中的弊端:
它的特徵是代理類和目標對象的類都是在編譯期間確定下來的,不利於程序上的擴展,上面示例中,如果客戶還想找一個「生產一批鞋子」的工廠,那麼還需要新增加一個代理類和一個目標類。如果客戶還需要很多其他的服務,就必須一一的添加代理類和目標類。那就需要寫很多的代理類和目標類
代理模式到底做了什麼?
我眼中的代理模式只有兩個關注點:協議和代理者
協議定義了一組方法,由某一個類負責實現。
代理者作為某個類的一個屬性,通常是另一個類的實例對象,可以負責完成原來這個類不方便或者無法完成的任務。
首先談一談代理者,在腦中重新回想一下代理模式的實現過程。在頁面B中定義一個代理對象的時候,好像和定義一個普通的property非常類似(除了 weak和id《delegate》>)。這也正是我對代理的概括:代理本來就是一個屬性而已,並沒有非常神秘。
當然,代理者並不只是一個類普通的屬性,否則我只需要重寫一下B的初始化方法即可達到同樣的效果:
self.BVC = [[BViewController alloc]initWithDelegate:self];
然後在BViewController.m中定義一個AViewController *AVC並在初始化方法中賦值即可。
注意到代理者在定義的時候,格式往往是這樣的:
id <SomeDelegate> delegate;
所以我對代理的優勢的理解是:
代理的核心優勢在於解耦
與直接聲明一個屬於某個固定的類的代理者相比,聲明為id的代理者具備兩個明星的優勢。
允許多個不同的類成為本類的代理。試想一下在本文例子中,如果頁面B可以跳轉回N個頁面,如果還是通過聲明一個普通對象的方式,那怎麼辦?
允許代理者的類還不固定。試想一下,UITableView也有delegate,它根本不知道那個類會成為它的代理者。
再看一看協議。協議更加簡單了。協議只是定義了一組方法。在代理模式中,完全可以不用在頁面B中定義一個協議,然後A再去遵循這個協議。直接調用A的方法即可。
個人認為協議的優點在於以下幾點:
可以利用Xcode的檢查機制。對於定義為@required的方法,如果實現了協議而沒有實現這個方法,編譯器將會有警告。這樣可以防止因為疏忽,忘記實現某個代碼的情況,而由於OC的運行時特性,這樣的錯誤往往在運行階段才會導致程序崩潰。
有利於代碼的封裝。如果一個類,實現了某個協議,那麼這個協議中的方法不必在.h中被聲明,就可以被定義協議的類調用。這樣可以減少一個類暴露給外部的方法。
有利於程序的結構化與層次化。一個協議往往是解決問題的某個方法,對於一個其他的不過卻類似的問題,我們只用再次實現協議即可,避免了自己再次構思一組方法。協議的繼承機制使得這一有點更加強大。
說了怎麼多,總結起來只有一句:代理模式並不神秘,只是一個經過了優化的小技巧(讓某個類持有另一個類的指針)。代理和協議也只是讓程序耦合度更低,結構感更強而已。
⑺ Java 中怎樣在程序中設置代理伺服器
importjava.io.BufferedReader;
importjava.io.InputStreamReader;
importjava.net.Authenticator;
importjava.net.HttpURLConnection;
importjava.net.InetSocketAddress;
importjava.net.PasswordAuthentication;
importjava.net.Proxy;
importjava.net.URL;
publicclassProxyDemo2{
publicstaticvoidmain(String[]args)throwsException{
URLurl=newURL("http://www.3lai8.com");
///創建代理伺服器
InetSocketAddressaddr=newInetSocketAddress("192.168.0.254",8080);
//Proxyproxy=newProxy(Proxy.Type.SOCKS,addr);//Socket代理
Proxyproxy=newProxy(Proxy.Type.HTTP,addr);//http代理
Authenticator.setDefault(newMyAuthenticator("username","password"));//設置代理的用戶和密碼
HttpURLConnectionconnection=(HttpURLConnection)url.openConnection(proxy);//設置代理訪問
InputStreamReaderin=newInputStreamReader(connection.getInputStream());
BufferedReaderreader=newBufferedReader(in);
while(true){
Strings=reader.readLine();
if(s!=null){
System.out.println(s);
}
}
}
{
privateStringuser="";
privateStringpassword="";
publicMyAuthenticator(Stringuser,Stringpassword){
this.user=user;
this.password=password;
}
(){
(user,password.toCharArray());
}
}
}
⑻ java 動態代理主要怎麼實現的
java動態代理主要是通過Proxy類的newProxyInstance()方法,該方法需要三個參(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h),其中分別為:
①:該對象的類載入器classloader
②:被代理類的類對象
③:一個InvocationHandler 處理器介面
InvocationHandler中有一個方法:invoke(Object proxy, Method method, Object[] args) ,通過顯式調用可以實現對代理對象的類方法進行操作,這里主要是採用反射的原理,SrpingAop就是利用這一點進行實現的。
⑼ java使用代理訪問網路的幾種方法
使用Proxy來對每個連接實現代理, 這種方法只能在jdk 1.5以上的版本使用(包含jdk1.5), 優點是可以單獨的設置每個連接的代理, 缺點是設置比較麻煩:
public static void main(String[] args) {
try {
URL url = new URL("http://www..com");
// 創建代理伺服器
InetSocketAddress addr = new InetSocketAddress("192.168.0.254",
8080);
// Proxy proxy = new Proxy(Proxy.Type.SOCKS, addr); // Socket 代理
Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); // http 代理
// 如果我們知道代理server的名字, 可以直接使用
// 結束
URLConnection conn = url.openConnection(proxy);
InputStream in = conn.getInputStream();
// InputStream in = url.openStream();
String s = IOUtils.toString(in);
System.out.println(s);
} catch (Exception e) {
e.printStackTrace();
}
}
不是很詳細, 有什麼問題還望大家指正
⑽ 如何用java使用代理
Java中,使用proxy是通過設置java環境變數來實現的,也就是JVM的系統屬性。
我們需要設置三個屬性,proxySet proxyHost和proxyPort。
proxySet 是個boolean類型的,可以設置為true或者false,true代表使用代理伺服器。
proxyHost 是代理伺服器的IP地址
proxyPort 是代理伺服器的埠地址。
我們有兩種方法設置這種系統屬性,
一種是命令行下運行Java程序的時候,通過參數付值
一種是在java源程序中設置。
第一種方法的格式如下:
java -DproxySet=true -DproxyHost=myProxyServer.come -DproxyPort=80 MyJavaApp
第二種方法,就是直接在源程序中通過系統屬性來寫,如下:
import java.util.Properties;
...
...
strProxy="221.15.5.67";
strPort="8080";
Properties systemProperties = System.getProperties();
systemProperties.setProperty("http.proxyHost",strProxy);
systemProperties.setProperty("http.proxyPort",strPort);
....
JDK1.3以上版本,只要設置了proxyHost和proxyPort就不用寫proxySet了。
那麼反過來,顯示這些系統屬性,就可以看到有沒有使用代理了。