程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 詳解java中靜態署理完成機制

詳解java中靜態署理完成機制

編輯:關於JAVA

詳解java中靜態署理完成機制。本站提示廣大學習愛好者:(詳解java中靜態署理完成機制)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解java中靜態署理完成機制正文


署理形式是經常使用的java設計形式,它的特點是署理類與拜托類有異樣的接口,署理類重要擔任為拜托類預處置新聞、過濾新聞、把新聞轉發給拜托類,和過後處置新聞等。署理類與拜托類之間平日會存在聯系關系關系,一個署理類的對象與一個拜托類的對象聯系關系,署理類的對象自己其實不真正完成辦事,而是經由過程挪用拜托類的對象的相干辦法,來供給特定的辦事。

JAVA各類靜態署理完成的比擬

接口

interface AddInterface{
 int add(int a, int b);
}

interface SubInterface{
 int sub(int a, int b);
}

完成類

class Arithmetic implements AddInterface, SubInterface{
 @Override
 public int sub(int a, int b) {
  return a-b;
 }

 @Override
 public int add(int a, int b) {
  return a+b;
 }
}

方法1: JDK自帶的靜態署理

1、完成方法

  Java在JDK1.3後引入的靜態署理機制,使我們可以在運轉期靜態的創立署理類。應用靜態署理完成AOP須要有四個腳色:被署理的類,被署理類的接口,織入器,和InvocationHandler,而織入器應用接口反射機制生成一個署理類,然後在這個署理類中織入代碼。被署理的類是AOP裡所說的目的,InvocationHandler是切面,它包括了Advice和Pointcut。

2、vInvocationHandler接口的完成

class JdkDPQueryHandler implements InvocationHandler{
 private Arithmetic real;
 public JdkDPQueryHandler(Arithmetic real){
  this.real = real;
 }
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  String methodName = method.getName();
  System.out.println(method);
  System.out.println("the method: " + methodName + "開端, 參數: "+Arrays.asList(args));
  Object result = method.invoke(real, args);
  System.out.println("the method: "+methodName+"停止, 成果: " + result);
  return result;
 }
}

3、創立署理類而且挪用署理類

public class Main{
 private static int a = 4, b = 2;
 
 public static Object createJDKProxy(Arithmetic real){
  Object proxyArithmetic = Proxy.newProxyInstance(real.getClass().getClassLoader(),
    real.getClass().getInterfaces(), new JdkDPQueryHandler(real)); 
  return proxyArithmetic;
 }
 
 public static void main(String[] args){
  Arithmetic real = new Arithmetic();
  Object proxyArithmetic = createJDKProxy(real);
  ((AddInterface)proxyArithmetic).add(a, b);
  ((SubInterface)proxyArithmetic).sub(a, b);
 }
}

方法2:靜態字節碼生成(cglib)

1、完成方法

  Enhancer和MethodInterceptor。Enhancer可以用來靜態的生成一個類,這個類可以繼續指定的一個類,完成指定的一些接口。同時,Enhancer在生成一個類之前須要指定一個Callback,當類辦法挪用時,辦法的履行被分派給這個Callback,MethodInterceptor是一個應用比擬多的繼續自Callback的接口,它只要一個辦法聲明。


2、接口InvocationHandler(jdk中)和接口MethodInterceptor(cglib中)比較

public interface MethodInterceptor extends Callback { 
 public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable; 
} 
public interface InvocationHandler { 
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; 
} 

    從參數組成上,methodInterceptor的輸出參數比Invocationhandler多1個,其實前3個參數對象的寄義與Invocationhandler的寄義是雷同的。
  第一個參數表現挪用辦法來自哪一個對象;
  第二個參數表現挪用辦法的Method對象;
  第三個參數表現此次挪用的輸出參數列表;
  多出來的參數是MethodProxy 類型的,它應當是cglib生成用來取代Method對象的一個對象,應用MethodProxy比挪用JDK本身的Method直接履行辦法效力會有晉升。
3、完成1

MethodInterceptor接口的完成

class CglibDPQueryInterceptor implements MethodInterceptor{
 private Arithmetic real;
 public CglibDPQueryInterceptor(Arithmetic real){
  this.real = real;
 }
 
 @Override
 public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  String methodName = method.getName();
  System.out.println(method);
  System.out.println("the method: " + methodName + "開端, 參數: "+Arrays.asList(args));
  //Object result = method.invoke(real, args);//兩種方法都是可以得
  Object result = proxy.invoke(real, args);
  System.out.println("the method: "+methodName+"停止, 成果: " + result);
  return result;
 }
}

創立署理類並挪用署理類

public class Main{
 private static int a = 4, b = 2;
 public static Object createCglibProxy(Arithmetic real){
   Enhancer enhancer = new Enhancer();
   enhancer.setCallback(new CglibDPQueryInterceptor(real));
   enhancer.setInterfaces(real.getClass().getInterfaces());
   return enhancer.create();
 }
 
 public static void main(String[] args){
  Arithmetic real = new Arithmetic();  
  Object proxyArithmetic = createCglibProxy(real);  
  ((AddInterface)proxyArithmetic).add(a, b);
  ((SubInterface)proxyArithmetic).sub(a, b);
 }
}

留意了,MethodProxy在對履行函數的時刻,供給了2個辦法

public Object invoke (Object obj, Object[] args) throws Throwable 
public Object invokeSuper(Object obj, Object[] args) throws Throwable

  個中,javadoc上說這個invoke()辦法可以用於雷同類中的其他對象的辦法履行,也就是說這個辦法中的obj須要傳入雷同一個類的另外一個對象(上述辦法中就是傳入了Arithmetic類的分歧對象),不然會進入無窮遞歸輪回(測試以後還真是湧現了StackOverflowError)。細心的想想就會發明,public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)中的target是完成的署理類對象,經由過程target挪用add()辦法時會觸發intercept()辦法被挪用,假如在intercept()辦法中再挪用method.invoke(target, args),就相當於add()辦法中又挪用add()辦法,招致無窮的遞歸輪回。然則假如履行method.invoke(real, args)則不會,由於real和target是統一個類分歧對象,real是真實邏輯主題,target是真實主題real的署理。

  上面一個例子來模仿一下:

interface SolveInterface{
 void solve();
}

class Real implements SolveInterface{
 public void solve(){
  System.out.println("Real Solve!");
 }
}

class Target extends Real{
 private Object obj;
 
 public void setObject(Object obj){
  this.obj = obj;
 }
 
 private void invoke(){
  try {
   Method method = SolveInterface.class.getMethod("solve", new Class[]{});
   method.invoke(obj, new Class[]{});
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 public void solve(){
  System.out.println("Target Solve!");
  invoke();
 }
}

public class Main{public static void main(String[] args) throws Exception{   
    Target target = new Target();
    target.setObject(new Real());//准確
    //target.setObject(target);//產生輪回挪用
    target.solve();
  }
}

其實Method的invoke()辦法會依據obj的類型去挪用對應的solve()辦法,也就是多態性。

4、完成2

  MethodInterceptor接口的完成

class CglibDPQueryInterceptor implements MethodInterceptor{
  
  @Override
  public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    String methodName = method.getName();
    System.out.println(method);
    System.out.println("the method: " + methodName + "開端, 參數: "+Arrays.asList(args));
    // 打印類信息 :target.getClass();省略
    Object result = proxy.invokeSuper(target, args);
    System.out.println("the method: "+methodName+"停止, 成果: " + result);
    return result;
  }
}

創立署理類並挪用署理類

public class Main{
  private static int a = 4, b = 2;
public static Object createCglibProxy(){
     Enhancer enhancer = new Enhancer();
     enhancer.setCallback(new CglibDPQueryInterceptor());
     enhancer.setSuperclass(Arithmetic.class);
     return enhancer.create();
  }
  
  public static void main(String[] args){
    Arithmetic real = new Arithmetic();

    Object proxyArithmetic = createCglibProxy();
    
    ((AddInterface)proxyArithmetic).add(a, b);
    ((SubInterface)proxyArithmetic).sub(a, b);
  }
}

  留意了,完成2中Enhancer 沒有設置接口,由於設置了Superclass了(也就是署理類的父類是Arithmetic),我們的署理類會繼續它,而Arithmetic曾經完成了我們的接口。為了證實這一點,可以在MethodInterceptor的 intercept辦法中打印 target.getClass()的類信息,你會發明cglib的兩種方法署理類的父類是分歧的。以下:

  完成1:

public class com.test.Arithmetic$$EnhancerByCGLIB$$4fa786eb extends java.lang.Object

  完成2:

public class com.test.Arithmetic$$EnhancerByCGLIB$$4fa786eb extends com.test.Arithmetic

方法3:javassist生成靜態署理(署理工場創立 或許 靜態代碼創立)  

  Javassist是一個編纂字節碼的框架,可讓你很簡略地操作字節碼。它可以在運轉期界說或修正Class。應用Javassist完成AOP的道理是在字節碼加載前直接修正須要切入的辦法。這比應用Cglib完成AOP加倍高效,而且沒太多限制,完成道理以下圖:

完成1:

接口的完成

class JavassistDPQueryHandler implements MethodHandler{

  @Override
  public Object invoke(Object target, Method method, Method proxy, Object[] args) throws Throwable {
    String methodName = method.getName();
    System.out.println(method);
    System.out.println("the method: " + methodName + "開端, 參數: "+Arrays.asList(args));
    Object result = proxy.invoke(target, args);
    System.out.println("the method: "+methodName+"停止, 成果: " + result);
    return result;
  }
}

創立署理類並挪用署理類

public class Main{
  private static int a = 4, b = 2;
public static Object createJavassistProxy() throws Exception{
    ProxyFactory factory = new ProxyFactory();
    factory.setSuperclass(Arithmetic.class);
    factory.setHandler(new JavassistDPQueryHandler());
    return factory.createClass().newInstance();
  }
  
  public static void main(String[] args) throws Exception{
    Arithmetic real = new Arithmetic();
    
    Object proxyArithmetic = createJavassistProxy();
    
    ((AddInterface)proxyArithmetic).add(a, b);
    ((SubInterface)proxyArithmetic).sub(a, b);
  }
}

留意:MethodHandler接口中invoke辦法的界說,以下:

public Object invoke(Object target, Method method, Method proxy, Object[] args)

method代表挪用辦法的Method對象,proxy是署理類發生並取代method的對象,不然用method.invoke(target, args)會發生無窮輪回挪用。

完成2:

  javassist應用靜態java代碼罕見署理進程和前文的辦法略有分歧。javassist外部可以經由過程靜態java代碼,生成字節碼。這類方法創立的靜態署理可以異常靈巧,乃至可以在運轉時發生營業邏輯。

//自界說攔阻器接口
interface InterceptorHandler { 
  
  /** 
   * 挪用靜態署理對象的辦法將反射本辦法,可在本辦法完成中添加相似AOP的事前過後操作,只要在本辦法體中參加以下代碼 
   * 被署理的辦法才會被履行,前往值將前往給署理最初前往給法式 
   * @param obj Object 被署理的對象 
   * @param method Method 被署理對象的辦法 
   * @param args Object[] 被署理對象的辦法的參數 
   * @return Object 被署理對象的辦法履行後的前往值 
   * @throws Throwable 
   */ 
  public Object invoke(Object obj, Method method, Object[] args) throws Throwable; 
} 

//攔阻器的完成
class InterceptorHandlerImpl implements InterceptorHandler{
  @Override
  public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    System.out.println(method);
    System.out.println("the method: " + methodName + "開端, 參數: "+Arrays.asList(args));
    Object result = method.invoke(obj, args);
    System.out.println("the method: "+methodName+"停止, 成果: " + result);
    return result;
  }
}


class MyProxyImpl { 
  /** 靜態署理類的類名後綴 */ 
  private final static String PROXY_CLASS_NAME_SUFFIX = "$MyProxy_"; 
  /** 攔阻器接口 */ 
  private final static String INTERCEPTOR_HANDLER_INTERFACE = "com.test.InterceptorHandler"; 
  /** 靜態署理類的類名索引,避免類名反復 */ 
  private static int proxyClassIndex = 1; 
   
  /** 
   * 裸露給用戶的靜態署理接口,前往某個接口的靜態署理對象,留意本署理完成需和com.cuishen.myAop.InterceptorHandler攔阻器合營 
   * 應用,即用戶要應用本靜態署理,需先完成com.cuishen.myAop.InterceptorHandler攔阻器接口 
   * @param interfaceClassName String 要靜態署理的接口類名, e.g test.StudentInfoService 
   * @param classToProxy String 要靜態署理的接口的完成類的類名, e.g test.StudentInfoServiceImpl 
   * @param interceptorHandlerImplClassName String 用戶供給的攔阻器接口的完成類的類名 
   * @return Object 前往某個接口的靜態署理對象 
   * @throws InstantiationException 
   * @throws IllegalAccessException 
   * @throws NotFoundException 
   * @throws CannotCompileException 
   * @throws ClassNotFoundException 
   * @see com.cuishen.myAop.InterceptorHandler 
   */ 
  public static Object newProxyInstance(String interfaceClassName, String classToProxy, String interceptorHandlerImplClassName) throws InstantiationException, IllegalAccessException, NotFoundException, CannotCompileException, ClassNotFoundException { 
    Class interfaceClass = Class.forName(interfaceClassName); 
    Class interceptorHandlerImplClass = Class.forName(interceptorHandlerImplClassName); 
    return dynamicImplementsInterface(classToProxy, interfaceClass, interceptorHandlerImplClass); 
  } 
   
  /** 
   * 靜態完成要署理的接口 
   * @param classToProxy String 要靜態署理的接口的完成類的類名, e.g test.StudentInfoServiceImpl 
   * @param interfaceClass Class 要靜態署理的接口類, e.g test.StudentInfoService 
   * @param interceptorHandlerImplClass Class 用戶供給的攔阻器接口的完成類 
   * @return Object 前往某個接口的靜態署理對象 
   * @throws NotFoundException 
   * @throws CannotCompileException 
   * @throws InstantiationException 
   * @throws IllegalAccessException 
   */ 
  private static Object dynamicImplementsInterface(String classToProxy, Class interfaceClass, Class interceptorHandlerImplClass) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException { 
    ClassPool cp = ClassPool.getDefault(); 
    String interfaceName = interfaceClass.getName(); 
    //靜態指定署理類的類名 
    String proxyClassName = interfaceName + PROXY_CLASS_NAME_SUFFIX + proxyClassIndex++; 
    //要完成的接口的包名+接口名 
    String interfaceNamePath = interfaceName; 
     
    CtClass ctInterface = cp.getCtClass(interfaceNamePath); 
    CtClass cc = cp.makeClass(proxyClassName); 
    cc.addInterface(ctInterface); 
    Method [] methods = interfaceClass.getMethods(); 
    for(int i = 0; i < methods.length; i++) { 
      Method method = methods[i]; 
      dynamicImplementsMethodsFromInterface(classToProxy, cc, method, interceptorHandlerImplClass, i); 
    } 
    return (Object)cc.toClass().newInstance(); 
  } 
   
  /** 
   * 靜態完成接口裡的辦法 
   * @param classToProxy String 要靜態署理的接口的完成類的類名, e.g test.StudentInfoServiceImpl 
   * @param implementer CtClass 靜態署理類的包裝 
   * @param methodToImpl Method 靜態署理類外面要完成的接口辦法的包裝 
   * @param interceptorClass Class 用戶供給的攔阻器完成類 
   * @param methodIndex int 要完成的辦法的索引 
   * @throws CannotCompileException 
   */ 
  private static void dynamicImplementsMethodsFromInterface(String classToProxy, CtClass implementer, Method methodToImpl, Class interceptorClass, int methodIndex) throws CannotCompileException { 
    String methodCode = generateMethodCode(classToProxy, methodToImpl, interceptorClass, methodIndex); 
    CtMethod cm = CtNewMethod.make(methodCode, implementer); 
    implementer.addMethod(cm); 
  } 
   
  /** 
   * 靜態組裝辦法體,固然署理外面的辦法完成其實不是簡略的辦法拷貝,而是反射挪用了攔阻器裡的invoke辦法,並將吸收到的參數停止傳遞 
   * @param classToProxy String 要靜態署理的接口的完成類的類名, e.g test.StudentInfoServiceImpl 
   * @param methodToImpl Method 靜態署理類外面要完成的接口辦法的包裝 
   * @param interceptorClass Class 用戶供給的攔阻器完成類 
   * @param methodIndex int 要完成的辦法的索引 
   * @return String 靜態組裝的辦法的字符串 
   */ 
  private static String generateMethodCode(String classToProxy, Method methodToImpl, Class interceptorClass, int methodIndex) { 
    String methodName = methodToImpl.getName(); 
    String methodReturnType = methodToImpl.getReturnType().getName(); 
    Class[] parameters = methodToImpl.getParameterTypes(); 
    Class[] exceptionTypes = methodToImpl.getExceptionTypes(); 
    StringBuffer exceptionBuffer = new StringBuffer(); 
    //組裝辦法的Exception聲明 
    if(exceptionTypes.length > 0) exceptionBuffer.append(" throws "); 
    for(int i = 0; i < exceptionTypes.length; i++) { 
      if(i != exceptionTypes.length - 1) exceptionBuffer.append(exceptionTypes[i].getName()).append(","); 
      else exceptionBuffer.append(exceptionTypes[i].getName()); 
    } 
    StringBuffer parameterBuffer = new StringBuffer(); 
    //組裝辦法的參數列表 
    for(int i = 0; i < parameters.length; i++) { 
      Class parameter = parameters[i]; 
      String parameterType = parameter.getName(); 
      //靜態指定辦法參數的變量名 
      String refName = "a" + i; 
      if(i != parameters.length - 1) parameterBuffer.append(parameterType).append(" " + refName).append(","); 
      else parameterBuffer.append(parameterType).append(" " + refName); 
    } 
    StringBuffer methodDeclare = new StringBuffer(); 
    //辦法聲明,因為是完成接口的辦法,所所以public 
    methodDeclare.append("public ").append(methodReturnType).append(" ").append(methodName).append("(").append(parameterBuffer).append(")").append(exceptionBuffer).append(" {\n"); 
    String interceptorImplName = interceptorClass.getName(); 
    //辦法體 
    methodDeclare.append(INTERCEPTOR_HANDLER_INTERFACE).append(" interceptor = new ").append(interceptorImplName).append("();\n"); 
    //反射挪用用戶的攔阻器接口 
    methodDeclare.append("Object returnObj = interceptor.invoke(Class.forName(\"" + classToProxy + "\").newInstance(), Class.forName(\"" + classToProxy + "\").getMethods()[" + methodIndex + "], "); 
    //傳遞辦法裡的參數 
    if(parameters.length > 0) methodDeclare.append("new Object[]{");  
    for(int i = 0; i < parameters.length; i++) { 
      //($w) converts from a primitive type to the corresponding wrapper type: e.g. 
      //Integer i = ($w)5; 
      if(i != parameters.length - 1) methodDeclare.append("($w)a" + i + ","); 
      else methodDeclare.append("($w)a" + i); 
    } 
    if(parameters.length > 0) methodDeclare.append("});\n"); 
    else methodDeclare.append("null);\n"); 
    //對換用攔阻器的前往值停止包裝 
    if(methodToImpl.getReturnType().isPrimitive()) { 
      if(methodToImpl.getReturnType().equals(Boolean.TYPE)) methodDeclare.append("return ((Boolean)returnObj).booleanValue();\n"); 
      else if(methodToImpl.getReturnType().equals(Integer.TYPE)) methodDeclare.append("return ((Integer)returnObj).intValue();\n"); 
      else if(methodToImpl.getReturnType().equals(Long.TYPE)) methodDeclare.append("return ((Long)returnObj).longValue();\n"); 
      else if(methodToImpl.getReturnType().equals(Float.TYPE)) methodDeclare.append("return ((Float)returnObj).floatValue();\n"); 
      else if(methodToImpl.getReturnType().equals(Double.TYPE)) methodDeclare.append("return ((Double)returnObj).doubleValue();\n"); 
      else if(methodToImpl.getReturnType().equals(Character.TYPE)) methodDeclare.append("return ((Character)returnObj).charValue();\n"); 
      else if(methodToImpl.getReturnType().equals(Byte.TYPE)) methodDeclare.append("return ((Byte)returnObj).byteValue();\n"); 
      else if(methodToImpl.getReturnType().equals(Short.TYPE)) methodDeclare.append("return ((Short)returnObj).shortValue();\n"); 
    } else { 
      methodDeclare.append("return (" + methodReturnType + ")returnObj;\n"); 
    } 
    methodDeclare.append("}"); 
    System.out.println(methodDeclare.toString()); 
    return methodDeclare.toString(); 
  } 
   
} 

public class Main{   
  public static void main(String[] args) throws Exception{  
     //分離對應 署理類要完成的接口類名, 須要署理類的類名, 用戶自界說攔阻器完成類的類名
    Object proxyArithmetic = MyProxyImpl.newProxyInstance("com.test.ArithmeticInterface", "com.test.Arithmetic", 
                                    "com.test.InterceptorHandlerImpl");
    ((ArithmeticInterface)proxyArithmetic).add(a, b);
    ((ArithmeticInterface)proxyArithmetic).sub(a, b);    
  }
}

打印一下靜態完成接口的代碼以下:

public int add(int a0,int a1) {
com.test.InterceptorHandler interceptor = new com.test.InterceptorHandlerImpl();
Object returnObj = interceptor.invoke(Class.forName("com.test.Arithmetic").newInstance(), Class.forName("com.test.Arithmetic").getMethods()[0], new Object[]{($w)a0,($w)a1});
return ((Integer)returnObj).intValue();
}
public int sub(int a0,int a1) {
com.test.InterceptorHandler interceptor = new com.test.InterceptorHandlerImpl();
Object returnObj = interceptor.invoke(Class.forName("com.test.Arithmetic").newInstance(), Class.forName("com.test.Arithmetic").getMethods()[1], new Object[]{($w)a0,($w)a1});
return ((Integer)returnObj).intValue();
}

以上就是關於java中靜態署理完成機制的具體引見,願望對年夜家的進修有所贊助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved