最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解java中動態(tài)代理實現(xiàn)機制

 更新時間:2016年01月19日 10:12:22   作者:小眼兒  
這篇文章主要為大家介紹了java中動態(tài)代理實現(xiàn)機制的相關(guān)資料,需要的朋友可以參考下

代理模式是常用的java設(shè)計模式,它的特征是代理類與委托類有同樣的接口,代理類主要負責(zé)為委托類預(yù)處理消息、過濾消息、把消息轉(zhuǎn)發(fā)給委托類,以及事后處理消息等。代理類與委托類之間通常會存在關(guān)聯(lián)關(guān)系,一個代理類的對象與一個委托類的對象關(guān)聯(lián),代理類的對象本身并不真正實現(xiàn)服務(wù),而是通過調(diào)用委托類的對象的相關(guān)方法,來提供特定的服務(wù)。

JAVA各種動態(tài)代理實現(xiàn)的比較

接口

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

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

實現(xiàn)類

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自帶的動態(tài)代理

1、實現(xiàn)方式

  Java在JDK1.3后引入的動態(tài)代理機制,使我們可以在運行期動態(tài)的創(chuàng)建代理類。使用動態(tài)代理實現(xiàn)AOP需要有四個角色:被代理的類,被代理類的接口,織入器,和InvocationHandler,而織入器使用接口反射機制生成一個代理類,然后在這個代理類中織入代碼。被代理的類是AOP里所說的目標,InvocationHandler是切面,它包含了Advice和Pointcut。

2、vInvocationHandler接口的實現(xiàn)

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 + "開始, 參數(shù): "+Arrays.asList(args));
  Object result = method.invoke(real, args);
  System.out.println("the method: "+methodName+"結(jié)束, 結(jié)果: " + result);
  return result;
 }
}

3、創(chuàng)建代理類并且調(diào)用代理類

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:動態(tài)字節(jié)碼生成(cglib)

1、實現(xiàn)方式

  Enhancer和MethodInterceptor。Enhancer可以用來動態(tài)的生成一個類,這個類可以繼承指定的一個類,實現(xiàn)指定的一些接口。同時,Enhancer在生成一個類之前需要指定一個Callback,當類方法調(diào)用時,方法的執(zhí)行被分配給這個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; 
} 

    從參數(shù)構(gòu)成上,methodInterceptor的輸入?yún)?shù)比Invocationhandler多1個,其實前3個參數(shù)對象的含義與Invocationhandler的含義是相同的。
  第一個參數(shù)表示調(diào)用方法來自哪個對象;
  第二個參數(shù)表示調(diào)用方法的Method對象;
  第三個參數(shù)表示此次調(diào)用的輸入?yún)?shù)列表;
  多出來的參數(shù)是MethodProxy 類型的,它應(yīng)該是cglib生成用來代替Method對象的一個對象,使用MethodProxy比調(diào)用JDK自身的Method直接執(zhí)行方法效率會有提升。
3、實現(xiàn)1

MethodInterceptor接口的實現(xiàn)

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 + "開始, 參數(shù): "+Arrays.asList(args));
  //Object result = method.invoke(real, args);//兩種方式都是可以得
  Object result = proxy.invoke(real, args);
  System.out.println("the method: "+methodName+"結(jié)束, 結(jié)果: " + result);
  return result;
 }
}

創(chuàng)建代理類并調(diào)用代理類

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在對執(zhí)行函數(shù)的時候,提供了2個方法

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

  其中,javadoc上說這個invoke()方法可以用于相同類中的其他對象的方法執(zhí)行,也就是說這個方法中的obj需要傳入相同一個類的另一個對象(上述方法中就是傳入了Arithmetic類的不同對象),否則會進入無限遞歸循環(huán)(測試之后還真是出現(xiàn)了StackOverflowError)。仔細的想一想就會發(fā)現(xiàn),public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)中的target是實現(xiàn)的代理類對象,通過target調(diào)用add()方法時會觸發(fā)intercept()方法被調(diào)用,如果在intercept()方法中再調(diào)用method.invoke(target, args),就相當于add()方法中又調(diào)用add()方法,導(dǎo)致無限的遞歸循環(huán)。但是如果執(zhí)行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);//發(fā)生循環(huán)調(diào)用
    target.solve();
  }
}

其實Method的invoke()方法會根據(jù)obj的類型去調(diào)用對應(yīng)的solve()方法,也就是多態(tài)性。

4、實現(xiàn)2

  MethodInterceptor接口的實現(xiàn)

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 + "開始, 參數(shù): "+Arrays.asList(args));
    // 打印類信息 :target.getClass();省略
    Object result = proxy.invokeSuper(target, args);
    System.out.println("the method: "+methodName+"結(jié)束, 結(jié)果: " + result);
    return result;
  }
}

創(chuàng)建代理類并調(diào)用代理類

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);
  }
}

  注意了,實現(xiàn)2中Enhancer 沒有設(shè)置接口,因為設(shè)置了Superclass了(也就是代理類的父類是Arithmetic),我們的代理類會繼承它,而Arithmetic已經(jīng)實現(xiàn)了我們的接口。為了證明這一點,可以在MethodInterceptor的 intercept方法中打印 target.getClass()的類信息,你會發(fā)現(xiàn)cglib的兩種方式代理類的父類是不同的。如下:

  實現(xiàn)1:

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

  實現(xiàn)2:

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

方式3:javassist生成動態(tài)代理(代理工廠創(chuàng)建 或者 動態(tài)代碼創(chuàng)建)  

  Javassist是一個編輯字節(jié)碼的框架,可以讓你很簡單地操作字節(jié)碼。它可以在運行期定義或修改Class。使用Javassist實現(xiàn)AOP的原理是在字節(jié)碼加載前直接修改需要切入的方法。這比使用Cglib實現(xiàn)AOP更加高效,并且沒太多限制,實現(xiàn)原理如下圖:

實現(xiàn)1:

接口的實現(xiàn)

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 + "開始, 參數(shù): "+Arrays.asList(args));
    Object result = proxy.invoke(target, args);
    System.out.println("the method: "+methodName+"結(jié)束, 結(jié)果: " + result);
    return result;
  }
}

創(chuàng)建代理類并調(diào)用代理類

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代表調(diào)用方法的Method對象,proxy是代理類產(chǎn)生并代替method的對象,否則用method.invoke(target, args)會產(chǎn)生無限循環(huán)調(diào)用。

實現(xiàn)2:

  javassist使用動態(tài)java代碼常見代理過程和前文的方法略有不同。javassist內(nèi)部可以通過動態(tài)java代碼,生成字節(jié)碼。這種方式創(chuàng)建的動態(tài)代理可以非常靈活,甚至可以在運行時產(chǎn)生業(yè)務(wù)邏輯。

//自定義攔截器接口
interface InterceptorHandler { 
  
  /** 
   * 調(diào)用動態(tài)代理對象的方法將反射本方法,可在本方法實現(xiàn)中添加類似AOP的事前事后操作,只有在本方法體中加入如下代碼 
   * 被代理的方法才會被執(zhí)行,返回值將返回給代理最后返回給程序 
   * @param obj Object 被代理的對象 
   * @param method Method 被代理對象的方法 
   * @param args Object[] 被代理對象的方法的參數(shù) 
   * @return Object 被代理對象的方法執(zhí)行后的返回值 
   * @throws Throwable 
   */ 
  public Object invoke(Object obj, Method method, Object[] args) throws Throwable; 
} 

//攔截器的實現(xiàn)
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 + "開始, 參數(shù): "+Arrays.asList(args));
    Object result = method.invoke(obj, args);
    System.out.println("the method: "+methodName+"結(jié)束, 結(jié)果: " + result);
    return result;
  }
}


class MyProxyImpl { 
  /** 動態(tài)代理類的類名后綴 */ 
  private final static String PROXY_CLASS_NAME_SUFFIX = "$MyProxy_"; 
  /** 攔截器接口 */ 
  private final static String INTERCEPTOR_HANDLER_INTERFACE = "com.test.InterceptorHandler"; 
  /** 動態(tài)代理類的類名索引,防止類名重復(fù) */ 
  private static int proxyClassIndex = 1; 
   
  /** 
   * 暴露給用戶的動態(tài)代理接口,返回某個接口的動態(tài)代理對象,注意本代理實現(xiàn)需和com.cuishen.myAop.InterceptorHandler攔截器配合 
   * 使用,即用戶要使用本動態(tài)代理,需先實現(xiàn)com.cuishen.myAop.InterceptorHandler攔截器接口 
   * @param interfaceClassName String 要動態(tài)代理的接口類名, e.g test.StudentInfoService 
   * @param classToProxy String 要動態(tài)代理的接口的實現(xiàn)類的類名, e.g test.StudentInfoServiceImpl 
   * @param interceptorHandlerImplClassName String 用戶提供的攔截器接口的實現(xiàn)類的類名 
   * @return Object 返回某個接口的動態(tài)代理對象 
   * @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); 
  } 
   
  /** 
   * 動態(tài)實現(xiàn)要代理的接口 
   * @param classToProxy String 要動態(tài)代理的接口的實現(xiàn)類的類名, e.g test.StudentInfoServiceImpl 
   * @param interfaceClass Class 要動態(tài)代理的接口類, e.g test.StudentInfoService 
   * @param interceptorHandlerImplClass Class 用戶提供的攔截器接口的實現(xiàn)類 
   * @return Object 返回某個接口的動態(tài)代理對象 
   * @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(); 
    //動態(tài)指定代理類的類名 
    String proxyClassName = interfaceName + PROXY_CLASS_NAME_SUFFIX + proxyClassIndex++; 
    //要實現(xiàn)的接口的包名+接口名 
    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(); 
  } 
   
  /** 
   * 動態(tài)實現(xiàn)接口里的方法 
   * @param classToProxy String 要動態(tài)代理的接口的實現(xiàn)類的類名, e.g test.StudentInfoServiceImpl 
   * @param implementer CtClass 動態(tài)代理類的包裝 
   * @param methodToImpl Method 動態(tài)代理類里面要實現(xiàn)的接口方法的包裝 
   * @param interceptorClass Class 用戶提供的攔截器實現(xiàn)類 
   * @param methodIndex int 要實現(xiàn)的方法的索引 
   * @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); 
  } 
   
  /** 
   * 動態(tài)組裝方法體,當然代理里面的方法實現(xiàn)并不是簡單的方法拷貝,而是反射調(diào)用了攔截器里的invoke方法,并將接收到的參數(shù)進行傳遞 
   * @param classToProxy String 要動態(tài)代理的接口的實現(xiàn)類的類名, e.g test.StudentInfoServiceImpl 
   * @param methodToImpl Method 動態(tài)代理類里面要實現(xiàn)的接口方法的包裝 
   * @param interceptorClass Class 用戶提供的攔截器實現(xiàn)類 
   * @param methodIndex int 要實現(xiàn)的方法的索引 
   * @return String 動態(tài)組裝的方法的字符串 
   */ 
  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(); 
    //組裝方法的參數(shù)列表 
    for(int i = 0; i < parameters.length; i++) { 
      Class parameter = parameters[i]; 
      String parameterType = parameter.getName(); 
      //動態(tài)指定方法參數(shù)的變量名 
      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(); 
    //方法聲明,由于是實現(xiàn)接口的方法,所以是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"); 
    //反射調(diào)用用戶的攔截器接口 
    methodDeclare.append("Object returnObj = interceptor.invoke(Class.forName(\"" + classToProxy + "\").newInstance(), Class.forName(\"" + classToProxy + "\").getMethods()[" + methodIndex + "], "); 
    //傳遞方法里的參數(shù) 
    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"); 
    //對調(diào)用攔截器的返回值進行包裝 
    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{  
     //分別對應(yīng) 代理類要實現(xiàn)的接口類名, 需要代理類的類名, 用戶自定義攔截器實現(xiàn)類的類名
    Object proxyArithmetic = MyProxyImpl.newProxyInstance("com.test.ArithmeticInterface", "com.test.Arithmetic", 
                                    "com.test.InterceptorHandlerImpl");
    ((ArithmeticInterface)proxyArithmetic).add(a, b);
    ((ArithmeticInterface)proxyArithmetic).sub(a, b);    
  }
}

打印一下動態(tài)實現(xiàn)接口的代碼如下:

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();
}

以上就是關(guān)于java中動態(tài)代理實現(xiàn)機制的詳細介紹,希望對大家的學(xué)習(xí)有所幫助。

相關(guān)文章

  • JavaWeb核心技術(shù)中Session與Cookie淺析

    JavaWeb核心技術(shù)中Session與Cookie淺析

    session的工作原理和cookie非常類似,在cookie中存放一個sessionID,真實的數(shù)據(jù)存放在服務(wù)器端,客戶端每次發(fā)送請求的時候帶上sessionID,服務(wù)端根據(jù)sessionID進行數(shù)據(jù)的響應(yīng)
    2023-02-02
  • Java如何優(yōu)雅實現(xiàn)數(shù)組切片和拼接操作

    Java如何優(yōu)雅實現(xiàn)數(shù)組切片和拼接操作

    在做一道算法題的時候用到數(shù)組合并,并且有性能要求,這里對Java數(shù)組合并進行總結(jié),下面這篇文章主要給大家介紹了關(guān)于Java如何優(yōu)雅實現(xiàn)數(shù)組切片和拼接操作的相關(guān)資料,需要的朋友可以參考下
    2024-04-04
  • SpringBoot3.3.0升級方案

    SpringBoot3.3.0升級方案

    本文介紹了由SpringBoot2升級到SpringBoot3.3.0升級方案,新版本的升級可以解決舊版本存在的部分漏洞問題,感興趣的可以了解一下
    2024-08-08
  • Nett中的心跳機制與斷線重連詳解

    Nett中的心跳機制與斷線重連詳解

    這篇文章主要介紹了Nett中的心跳機制與斷線重連詳解,我們以客戶端發(fā)送心跳為例,平時我們的心跳實現(xiàn)方式可能是搞個定時器,定時發(fā)送是吧,但是在Netty中卻不一樣,心跳被稱為空閑檢測,需要的朋友可以參考下
    2023-12-12
  • springboot如何集成mysql

    springboot如何集成mysql

    這篇文章主要介紹了springboot如何集成mysql問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 基于Springboot使用logback的注意事項

    基于Springboot使用logback的注意事項

    這篇文章主要介紹了Springboot使用logback的注意事項,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java微信開發(fā)第二步 獲取消息和回復(fù)消息

    java微信開發(fā)第二步 獲取消息和回復(fù)消息

    這篇文章主要為大家分享java微信開發(fā)的第二步,如何獲取消息和回復(fù)消息,感興趣的小伙伴們可以參考一下
    2016-05-05
  • 詳解Spring Boot使用Maven自定義打包方式

    詳解Spring Boot使用Maven自定義打包方式

    這篇文章主要介紹了Spring Boot使用Maven自定義打包方式,本文通過多種方式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • Java SpringBoot自動裝配原理詳解及源碼注釋

    Java SpringBoot自動裝配原理詳解及源碼注釋

    SpringBoot的自動裝配是拆箱即用的基礎(chǔ),也是微服務(wù)化的前提。其實它并不那么神秘,我在這之前已經(jīng)寫過最基本的實現(xiàn)了,大家可以參考這篇文章,來看看它是怎么樣實現(xiàn)的,我們透過源代碼來把握自動裝配的來龍去脈
    2021-10-10
  • mybatis-plus?如何使用雪花算法ID生成策略

    mybatis-plus?如何使用雪花算法ID生成策略

    這篇文章主要介紹了mybatis-plus如何使用雪花算法ID生成策略,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評論

西宁市| 桂东县| 团风县| 诸城市| 光山县| 澜沧| 洛隆县| 兴文县| 玉门市| 吉木萨尔县| 奉贤区| 宣威市| 酒泉市| 临夏市| 边坝县| 沾化县| 大城县| 介休市| 冷水江市| 鄂尔多斯市| 嘉峪关市| 固安县| 永定县| 平武县| 宁武县| 双柏县| 库伦旗| 河西区| 哈密市| 资阳市| 博客| 若尔盖县| 大安市| 焦作市| 东安县| 广西| 海安县| 六安市| 樟树市| 贺州市| 司法|