动态代理
实例参考SSM-Mybatis注解使用
- JDK动态代理原理
- 创建一个继承Proxy和实现被代理对象的接口的新类,在每次调用方法的时候都会调用invoke
- 它需要三个参数,前两个参数的意思是在同一个classloader下通过接口创建出一个对象,该对象需要一个属性,也就是第三个参数,它是一个InvocationHandler,每次调用会执行InvocationHandler的invoke方法
- 这里可以看出代理类实现newProxyInstance的第二个参数interfaces的所有接口,所以只能强转成其中的接口
- 如果只希望产生接口的代理可以使用new Class[]{BookMapper.class}
- 如过要产生实现类的代理使用class.getInterfaces()即可
public final class XXX extends Proxy implements XXX public final String SayHello(String paramString) { try { return (String)this.h.invoke(this, m4, new Object[] { paramString }); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); }
- cglib动态代理
cglib的原理是这样,它生成一个继承B的类型C(代理类),这个代理类持有一个MethodInterceptor,我们setCallback时传入的。 C重写所有B中的方法(方法名一致),然后在C中,构建名叫“CGLIB”+“$父类方法名$”的方法(下面叫cglib方法,所有非private的方法都会被构建),方法体里只有一句话super.方法名(),可以简单的认为保持了对父类方法的一个引用,方便调用
自定义工具类public class CglibProxy implements MethodInterceptor { // 根据一个类型产生代理类,此方法不要求一定放在MethodInterceptor中 public Object CreatProxyedObj(Class<?> clazz) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(clazz); // 因为是生成子类所以必须指定父类 enhancer.setCallback(this); // 执行intercept方法的回调 return enhancer.create(); } @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { // 这里增强 System.out.println("收钱"); return arg3.invokeSuper(arg0, arg2); } }
public class MyProxy implements InvocationHandler { private Invoke invoke; public MyProxy(Invoke invoke) { this.invoke = invoke; } private MyProxy() {} // public <T> T getProxy(Class<? extends T> target){ return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return invoke.run(method, args); } public interface Invoke{ Object run(Method method, Object[] args) throws Throwable; } } -- 使用 B b = new B(); MyProxy proxy = new MyProxy((method, args) -> { System.out.println("pre"); method.invoke(b,args); System.out.println("after"); return null; }); A a = proxy.getProxy(B.class); a.show();
ThreadLocal
-
每个Thread维护着一个ThreadLocalMap的引用
-
ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储
-
ThreadLocal创建的副本是存储在自己的threadLocals中的,也就是自己的ThreadLocalMap。
-
ThreadLocalMap的键值为ThreadLocal对象,而且可以有多个threadLocal变量,因此保存在map中
-
在进行get之前,必须先set,否则会报空指针异常,当然也可以初始化一个,但是必须重写initialValue()方法。
-
ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。