实现简单的Aop

    xiaoxiao2022-07-13  144

    使用jdk的动态代理

    创建Custom接口和实现类

    public interface Custom { public void NeedApple(); public void NeedPen(); } public class CustomImpl implements Custom { @Override public void NeedApple() { System.out.println("我需要苹果"); } @Override public void NeedPen() { System.out.println("我需要钢笔"); } }

    创建通知接口和是实现类

    public interface DoSomething { public void before(); public void after(); } public class DoSomethingImpl implements DoSomething { @Override public void before() { System.out.println("...before..."); } @Override public void after() { System.out.println("...after..."); } }

    创建代理类

    import TestSimpleAop.NeedToProxyed.CustomImpl; import TestSimpleAop.ProxyClass.DoSomethingImpl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ExcuteProxy implements InvocationHandler { CustomImpl custom;//需要在这里讲类导入进来,一边下面的invoke的方法里使用。 DoSomethingImpl doSomething; //相当于这里实现了注入的方法 public Object getProxy(CustomImpl custom,DoSomethingImpl doSomething){ this.custom = custom; this.doSomething = doSomething; return Proxy.newProxyInstance(this.custom.getClass().getClassLoader(), this.custom.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //通过反射机制来得到方法 Class clazz = this.doSomething.getClass(); //这里的class..参数需要协商newClass{},但是在{}里不写任何的东西,不然会出错 //之前在这里写上了Method.class经过调试发现在源码的 //public final class Class<T> implements java.io.Serializable, // GenericDeclaration, // Type, // AnnotatedElement //这个类中的private static boolean arrayContentsEq(Object[] a1, Object[] a2)方法中 //回去判断a1.length != a2.length 如果在newClass{}里添加东西会导致其判断为正确而返回 //false而报错 Method beforemethod = clazz.getDeclaredMethod("before",new Class[]{}); //这里的第二个参数也是不要写成this.doSomething.getclass(),这样也会出错,写成args beforemethod.invoke(this.doSomething,args); Object obj = method.invoke(this.custom,args); Method aftermethod = clazz.getDeclaredMethod("after",new Class[]{}); aftermethod.invoke(this.doSomething,args); return obj; } }

    编写testRun类

    public class TestRun { public static void main(String[] args) { ExcuteProxy ep = new ExcuteProxy(); //将其返回给Custom的接口 Custom custom = (Custom) ep.getProxy(new CustomImpl(),new DoSomethingImpl()); custom.NeedApple(); } }

    参考的连接 参考链接中的关于自动的实现aop那一块有错误,本文已经给与纠正。

    总结

    通过这种方法可以进一步的理解Spring对aop的实现。在Spring中是由一条拦截链来实现对于各种前置后置、Exception、huanrao或者是returnafter。在完成了拦截链的创建之后就会去执行链中的每一个拦截器。在执行拦截器的时候很像上面的执行过程。不过不一样的地方是在Spring中不需要在代理类中写死被代理对象和通知对象。Spring在创建aop的时候使用了代理对象,先不管是jdk的还是cglib的。总之在执行真正的方法比如 custom.NeedApple();的时候,执行的就不是我们定义的Custom的NeedApple()方法了。通过对其代理对象的class的查看可以知道在其代理对象的NeedApple()方法中其实已经将我们设计的模式写进去了。比如我们需要在方法的前后放置方法来实现各种功能,那么再其代理对象的class的方法中就已经写好了,只不过这个过程是被掩盖的。所以在ExcuteProxy 类中的invoke方法其实就是代理对象中的NeedApple()的这个是模样。所以当在testRun类中执行方法custom.NeedApple();的时候不要去看原本的Custom类中的方法。需要去查看其代理对象中的方法。这样就一目了然。所以可以说这个其实是对原本的类中的方法进行了改写。所以如果原本的方法中的修饰符为final那么使用cglib就会出问题,因为cglib其实是使用类的子类来实现代理的。而Spring拿取通知(advice)和被代理对象都应该是在ico的容器里拿取。所以aop其实是对ioc容器里的bean的二次代理。知道了底层的原理,再看Spring的aop就不会再显得懊恼了。

    最新回复(0)