通过 Spring AOP 注解实现自动代理

jopen 10年前

最近在做一个数据对接项目,通过Hessian与其他企业对接数据。但是公司电脑不能上网只能通过DL上网。如果每个方法都写代理的代码太繁琐,而 且项目发布到服务器上的时候服务器是可以上网的。即便通过配置文件配置各个类是否使用代理,但是当发布的时候修改配置文件的内容也会比较多。所以就想到了 通过注解+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的配置就可以了。

  来源:王成委的博客