Dynamic proxy framework mybatis

Frankly, dynamic proxies in their daily work I did not how used, rare also used by others, seen many examples online, but I felt little difference with decorative patterns are enhanced functions, what pre- and post , in fact, also the case, as the interview is often asked mybatis frame mapper interface to this one, and ultimately, to wander dynamic proxy. Speaking inscrutable, in fact, just ignore their own, or it also includes the interviewer. However, after a careful reading of the mybatis this piece of source code, understand the dynamic proxy slightly strengthened.

 

Consider the following example of a dynamic proxy jdk

public interface UserService {
    Object sayHello(String name);
}

 

public class UserServiceImpl implements UserService {
    @Override
    public Object sayHello(String name) {
        System.out.println("sayHello方法被调用。。。");
        return "hello " + name;
    }
}

 

public class UserProxy implements InvocationHandler {
    private Object target;

    public UserProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置增强。。。");
        Object result = method.invoke(target, args);
        System.out.println("后置增强。。。");
        return result;
    }
}

 

Test code

public class ProxyTest {
    public static void main(String[] args) {
        UserServiceImpl userServiceImpl = new UserServiceImpl();
        UserProxy userProxy = new UserProxy(userServiceImpl);
        UserService userService = (UserService) Proxy.newProxyInstance(userServiceImpl.getClass().getClassLoader(),
                       userServiceImpl.getClass().getInterfaces(), userProxy); Object result
= userService.sayHello("admin"); System.out.println("结果:" + result); } }

 

Print run as follows:

Front enhancement. . . 
sayHello method is called. . . 
Rear enhanced. . .
The results: the Hello ADMIN

 

This example is similar to online a lot, just in terms of functionality, this sample and complete a decorative pattern looks like nothing more than to use a dynamic proxy invoke () method, if the decorative pattern, should also be sayHello () method only,

This difference between a ghost. However, let us look at mybatis framework is how to use dynamic proxies, saw perhaps there will be a different feeling. . .

 

mybatis frame Mapper dynamic interface agent mainly related to source the following two classes

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.ibatis.session.SqlSession;

/**
 * @author Lasse Voss
 */
public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethod> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}

 

import java.io.Serializable;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;

import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.SqlSession;

/**
 * @author Clinton Begin
 * @author Eduardo Macarron
 */
public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (method.isDefault()) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
    return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
  }

  private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
      throws Throwable {
    final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
        .getDeclaredConstructor(Class.class, int.class);
    if (!constructor.isAccessible()) {
      constructor.setAccessible(true);
    }
    final Class<?> declaringClass = method.getDeclaringClass();
    return constructor
        .newInstance(declaringClass,
            MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
                | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
        .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
  }
}

 

Urinary mybatis framework, basically to create an object with the factory, MapperProxyFactory class is to create MapperProxy factory class, and this is the place of MapperProxy Mapper interface to work, perhaps it is because

For this reason, it is called proxy mode now!

 

Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);

 

 
 
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

 

Then about my understanding of the above, this method:

The method is to create a proxy object, the method has three parameters.

The first argument: ClassLoader, class loader, for understanding proxy mode, I think is not important.

The first two parameters: interfaces, interface class, my understanding is that it is a big boss, he told henchman work, from basic not work.

The first three parameters: InvocationHandler, the big boss's henchman, instead of the big boss man, as to how the specific work, you have to look at its invoke () method has.

 

In mybatis framework, Mapper interfaces is the big boss, henchman is MapperProxy, specifically how to work is the following code

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (method.isDefault()) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

This code is read, and instantly feel the most dynamic and former agents of very different examples of what the front, rear, there are not used to, perhaps a dynamic proxy purpose, is simply not to the so-called pre- and post-design it (perhaps just incidentally it). Text analysis through the front known source, the database operation, will not go if () {} else if () {} logic, go directly behind logic, the logic behind this is actually encapsulate the Executor operation of the database objects, here I will not say.

 

Why not enter if logic?

 if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      }

By way of example foremost know, invoke method calls the true reality approach, in terms of the interface Mapper, it simply did not materialize, so it must not take this logic. As else if (), totally did not understand!

 

to sum up:

Every time I think dynamic proxy, I think decorative, about what you do at work? Inspired by mybatis framework, I think, if the interface has implemented the use of decorative patterns can enhance existing features,

If only just one interface, and does not provide an implementation, this time in order to complete the function interface (the interface is a basket case, are what matter is not dry), you can choose dynamic proxies, after all, when using dynamic proxies, the real Officer

Is InvocationHandler # invoke, Proxy class jdk is to provide an interface with the Director-General InvocationHandler real binding relationship. 

 

 

 

 

The figure is equivalent to the interface county caller dynamic proxies; the big boss is the interface itself; henchman is InvocationHandler; dog chain is Proxy.

Finally, look again at the example to deepen the understanding of:

/ ** 
 * boss 
 * / 
public  interface IUserService { 
    Object the sayHello (String name); 
}
/ ** 
 * henchman 
 * / 
public  class userProxy the implements of InvocationHandler {
     // Here reference may be transmitted by the constructor, invoke and execute business logic method 


    @Override 
    public Object invoke (Object Proxy, Method, Method, Object [] args) throws the Throwable { 
        System.out.println ( "I henchman ....." );
         return "Hello" + args [0 ]; 
    } 

} / **
 * 县长
 */
public class UserProxyTest {
    public static void main(String[] args) {
        IUserService userService = (IUserService) Proxy.newProxyInstance(IUserService.class.getClassLoader(), 
                                new Class[]{IUserService.class}, new UserProxy()); Object result = userService.sayHello("狗腿子"); System.out.println(result); } }

Print results are as follows:

 

over! IUserService interface is not implemented class specific implementation sayHello is done in UserProxy # invoke () method, of course, this is just a simple example, in a real business code, can by userProxy constructor transmission parameters (including the objects) and then call these parameters to complete the complex business logic!

 

By this article, it should be possible to decorate with the use of proxies distinguish the scene!

 

 

 

 

 

Guess you like

Origin www.cnblogs.com/z-qinfeng/p/11901989.html