通過 Spring AOP 註解實現自動代理

王成委的部落格發表於2015-03-13

最近在做一個資料對接專案,通過Hessian與其他企業對接資料。但是公司電腦不能上網只能通過代理上網。如果每個方法都寫代理的程式碼太繁瑣,而且專案釋出到伺服器上的時候伺服器是可以上網的。即便通過配置檔案配置各個類是否使用代理,但是當釋出的時候修改配置檔案的內容也會比較多。所以就想到了通過註解+AOP的方式實現自動呼叫代理。

HTTP代理介面如下,其中的startProxy()為開始使用代理,endProxy()為結束使用代理,在需要用到的時候開啟,不用的時候關閉,這樣避免其他不需要使用代理的介面出現問題。

package com.tiamaes.gjds.proxy;

/**  
 * <p>類描述: Http代理介面</p>
 * <p>建立人:王成委  </p>
 * <p>建立時間:2015年1月16日 上午9:00:53  </p>
 * <p>版權說明: © 2015 Tiamaes </p>
 */
public interface HttpProxy {

    public void startProxy();

    public void endProxy();

    public String getUsername();

    public void setUsername(String username);

    public String getPassword();

    public void setPassword(String password);

    public String getHost();

    public void setHost(String host);

    public int getPort();

    public void setPort(int port);
}

實現類如下

package com.tiamaes.gjds.proxy;

import java.net.Authenticator;
import java.net.PasswordAuthentication;

/**  
 * <p>類描述: Http代理</p>
 * <p>建立人:王成委  </p>
 * <p>建立時間:2015年1月15日 下午5:09:16  </p>
 * <p>版權說明: © 2015 Tiamaes </p>
 */
public class ProxyAuthentication extends Authenticator implements HttpProxy{
    private String username;
    private String password;
    private String host;
    private int port;

    public ProxyAuthentication(){

    }

    public ProxyAuthentication(String host,int port){
        this.host = host;
        this.port = port;
    }

    public ProxyAuthentication(String host,int port,String username,String password){
        this.host = host;
        this.port = port;
        this.username = username;
        this.password = password;
    }

    public PasswordAuthentication getPasswordAuthentication(){
        return new PasswordAuthentication(username,password.toCharArray());
    }

    /**
     * 開始使用代理
     * @author 王成委
     */
    public void startProxy(){
        System.setProperty("http.proxySet", "true");
        System.setProperty("http.proxyHost", host);
        System.setProperty("http.proxyPort", String.valueOf(port));

        if(username != null && !"".equals(username))
            Authenticator.setDefault(this);
    }

    /**
     * 停止使用代理
     * @author 王成委
     */
    public void endProxy(){
        //System.se
        System.setProperty("http.proxySet", "false");
        System.setProperty("http.proxyHost", "");
        System.setProperty("http.proxyPort", "");
        Authenticator.setDefault(null);
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

}

註解的程式碼如下

package com.tiamaes.gjds.dxp.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**  
 * <p>類描述: 使用代理設定 </p>
 * <pre>:eg
 * @UseProxy
 * public Object getByHttp(){
 *  ......
 * }
 * </pre>
 * <p>建立人:王成委  </p>
 * <p>建立時間:2015年2月9日 下午4:41:27  </p>
 * <p>版權說明: © 2015 Tiamaes </p>
 * @see com.tiamaes.gjds.dxp.aop.ProxyManager
 * 
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented
public @interface UseProxy {

}

AOP切面的程式碼如下,這個是核心程式碼,原理就是監控帶有UseProxy註解的方法,在方法執行前呼叫startProxy啟動代理在方法執行結束後呼叫endProxy結束代理。

package com.tiamaes.gjds.dxp.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import com.tiamaes.gjds.proxy.HttpProxy;

/**  
 * <p>類描述: 通過註解{@link com.tiamaes.gjds.dxp.annotation.UseProxy}配置方法使用Http代理 </p>
 * <p>建立人:王成委  </p>
 * <p>建立時間:2015年2月9日 下午4:42:06  </p>
 * <p>版權說明: © 2015 Tiamaes </p>
 * @see com.tiamaes.gjds.dxp.annotation.UseProxy
 */
@Aspect
public class ProxyManager {

    private HttpProxy httpProxy;
    private boolean proxyEnabled = true;

    public void setHttpProxy(HttpProxy httpProxy) {
        this.httpProxy = httpProxy;
    }

    public void setProxyEnabled(boolean proxyEnabled) {
        this.proxyEnabled = proxyEnabled;
    }

    @Pointcut("@annotation(com.tiamaes.gjds.dxp.annotation.UseProxy)")  
    public void proxyAspect() {

    }

    @Around("proxyAspect()")
    public Object doInvoke(ProceedingJoinPoint joinPoint) throws Throwable{
        if(httpProxy == null || !proxyEnabled){
            return joinPoint.proceed();
        }
        this.httpProxy.startProxy();
        Object result = joinPoint.proceed();
        this.httpProxy.endProxy();
        return result;
    }
}

Spring配置如下

<bean id="httpProxy" class="com.tiamaes.gjds.proxy.ProxyAuthentication">
        <property name="host" value="192.168.38.69"/>
        <property name="port" value="808" />
        <property name="username" value="user001" />
        <property name="password" value="123456" />
    </bean>
    <bean id="proxyManager" class="com.tiamaes.gjds.dxp.aop.ProxyManager">
        <property name="httpProxy" ref="httpProxy" />
    </bean>

使用方法如下

 @UseProxy
    @Override
    public List<DriverInfo> GetDriverInfos(List<QueryInfo> queryInfos,
            int page, int pageSize) throws HessianException{
        List<DriverInfo> drivers = null;
        try {
            KeliDriverQueryApi api = this.createApiByUrlKey(KeliDriverQueryApi.API_URL, KeliDriverQueryApi.class);
            drivers = api.GetDriverInfos(queryInfos, page, pageSize);
        } catch (MalformedURLException e) {
            throw new ConnotGetHessianApiException("無法建立遠端介面");
        }
        return drivers;
    }

只需要在方法上面加一個註解就可以實現自動呼叫HTTP代理。在不需要HTTP代理的時候直接把Spring配置檔案中關的內容刪掉就可以了,其實直接刪除ProxyManager的配置就可以了。

相關文章