实现简单AOP

AOP都是使用设计模式的代理模式来实现的jdk的是通过动态代理 且目标类必须有接口为啥要有接口 https://blog.csdn.net/ray890206/article/details/70146029 这篇文章解释得比较简单易懂 笔者也无法分析好 所以建议还是百度一下 当然最后会有自己的看法现在先来实现JDK 的动态代理首先是需要被增强的目标类与目标类的接口public interface...
摘要由CSDN通过智能技术生成

AOP都是使用设计模式的代理模式来实现的

jdk的是通过动态代理 且目标类必须有接口

为啥要有接口 建议可以看看 这篇 https://blog.csdn.net/zhangerqing/article/details/42504281 笔者下面也有JDK1.7的源码分析,该博客是分析JDK1.8的 出入不大 基本一样 

现在先来实现JDK 的动态代理

首先是需要被增强的目标类与目标类的接口

public interface SourceAble {
    void method();
}
public class Source implements SourceAble {
    @Override
    public void method() {
        System.out.println("this is source method");
    }
}

实现自己的 InvocationHandler  这里实现切面的增强 这里前后都做了增强 在Spring就是@Around 切面

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {

    private Object target; //们既然要做代理,我们必须知道我们是给谁做代理,这里的obj就是被代理者。

    MyInvocationHandler() {
        super();
    }

    public MyInvocationHandler(Object target) {
        super();
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(target,args);
        atfer();
        return result;
    }

    private void atfer() {
        System.out.println("after proxy!");
    }
    private void before() {
        System.out.println("before proxy!");
    }
}

这样就完成切面的操作了 是不是很简单

然后调用jdk反射包的代理类来实现,下面是测试类

public class Test {
    public static void main(String[] args) {
      
        System.out.println("-----------动态代理--------------");
       //动态代理测试
        SourceAble sourceAble1 = new Source();//被代理的对象
        InvocationHandler invocationHandler = new MyInvocationHandler(sourceAble1);//
        //代理对象
        SourceAble dynamicProxy = (SourceAble) java.lang.reflect.Proxy.newProxyInstance(sourceAble1.getClass().getClassLoader(),sourceAble1.getClass().getInterfaces(),invocationHandler);
        dynamicProxy.method();
    }

}

执行动态代理类的方法

接下来我们也来简单用cglib来实现AOP

首先导入cglib包

目标类User

public class User {
    private String name;
    public void playName(String name){
      System.out.println(" 这是 palyName 方法 参数被偷换啦!参数是:"+name);
    }
    public void save(){
        System.out.println("this is save 方法 :";
    }
}

Cglib代理 这里是实现MethodInterceptor来做到切面的增强

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor{

    public Object getProxy(Class<?> clazz) {//这里需要知道代理的对象 传入被代理对象的class对象
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();//返回代理对象
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy proxy) throws Throwable {

        // 拦截父类所有方法的调用
        System.out.println(method.getName()+":方法执行前......");
        //通过代理类调用父类中的方法
        Object result = proxy.invokeSuper(o,new Object[]{"ssss"});//这里可以拦截所有的父类方法参数
        System.out.println(method.getName()+"方法执行结果:"+result);//这里可以拦截所有父类方法的返回值
        System.out.println(method.getName()+":方法执行后");
        return result;
    }
}
然后是测试类
 
public class Test {

    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        User user = (User) proxy.getProxy(new User().getClass());
        user.playName("kaizen");//明明是kaizen 输出是SSSS 代理模式坑爹啊
        user.save("kaizen");
    }


}

测试结果 这里注意一下参数会拦截所有的方法!


这里还能修改参数,执行结果,不过使用asm好像会导致性能问题,由于笔者能力有限,也说不出个所以然~

最后对JDK动态代理为什么要实现接口,可以看看笔者写的是否对不对,如果有错麻烦指导一下,本人查看的是JDK1.7

为啥要有接口  

首先看 newProxyInstance这个方法里 

 @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)//参数
        throws IllegalArgumentException
    {
        if (h == null) {
            throw new NullPointerException();
        }

        final Class<?>[] intfs = interfaces.clone();//接口浅拷贝
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {//检查是否能访问 这边不研究
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);//这边就是生成代理对象的class

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            final Constructor<?> cons = cl.getConstructor(constructorParams);//这里获得的是代理对象放置InvocationHandler的构造函数
            final InvocationHandler ih = h;
            if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
                // create proxy instance with doPrivilege as the proxy class may
                // implement non-public interfaces that requires a special permission
                return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    public Object run() {
                        return newInstance(cons, ih);
                    }
                });
            } else {
                return newInstance(cons, ih);//调用构造函数生成代理类
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString());
        }
    }

这里还能补充一个知识点:

浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。


重点应该在

Class<?> cl = getProxyClass0(loader, intfs);//这边就是生成代理对象的class
 private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

proxyClassCache是个缓存

先从缓存里查一下,如果存在,直接返回代理对象的class,不存在就新创建代理对象的class。具体的代码

 
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
 
WeakCache(BiFunction<K, P, ?> subKeyFactory,
                BiFunction<K, P, V> valueFactory)
 public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // lazily construct a Factory
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }
 

Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
apply()是Proxy类的内部类ProxyClassFactory实现其接口的一个方法
R apply(T t, U u);
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值