• JavaEE---------简单使用JDK动态代理模拟Spring的AOP


    Spring的面向切面编程可以使用AspectJ来实现

    那如何实现的呢?在有接口的被委托类可以实现其接口,没有借口的用CGLIB可以动态生成

    下面就来模拟一下用接口实现

    先创建一个接口:

    UserDAO.java

    package com.bq;
    
    public interface UserDAO {
        public void addUser();
    }

    实现它的UserDAOImpl.java

    package com.bq;
    
    public class UserDAOImpl implements UserDAO {
    
        @Override
        public void addUser() {
            System.out.println("用户已保存");
        }
    
    }

    编写委托类:LogInterceptor.java

    package com.bq;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class LogInterceptor implements InvocationHandler {
        //目标对象
        private Object target;
        
        public Object getTarget() {
            return target;
        }
    
        public void setTarget(Object target) {
            this.target = target;
        }
        
        //创建一个方法以便在注入前调用
        public void beforeMethod(Method m) {
            
            System.out.println("在执行方法之前调用");
            System.out.println(m.getName() + " start");
        }
        /*
         * 重写接口里的方法
         * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
         * 
         */
        
         /*相关说明,理解每个参数的意思
         * Processes a method invocation on a proxy instance and returns
         * the result.  This method will be invoked on an invocation handler
         * when a method is invoked on a proxy instance that it is
         * associated with.
         *
         * @param   proxy the proxy instance that the method was invoked on
         *
         * @param   method the {@code Method} instance corresponding to
         * the interface method invoked on the proxy instance.  The declaring
         * class of the {@code Method} object will be the interface that
         * the method was declared in, which may be a superinterface of the
         * proxy interface that the proxy class inherits the method through.
         *
         * @param   args an array of objects containing the values of the
         * arguments passed in the method invocation on the proxy instance,
         * or {@code null} if interface method takes no arguments.
         * Arguments of primitive types are wrapped in instances of the
         * appropriate primitive wrapper class, such as
         * {@code java.lang.Integer} or {@code java.lang.Boolean}.
         *
         * @return  the value to return from the method invocation on the
         * proxy instance.  If the declared return type of the interface
         * method is a primitive type, then the value returned by
         * this method must be an instance of the corresponding primitive
         * wrapper class; otherwise, it must be a type assignable to the
         * declared return type.  If the value returned by this method is
         * {@code null} and the interface method's return type is
         * primitive, then a {@code NullPointerException} will be
         * thrown by the method invocation on the proxy instance.  If the
         * value returned by this method is otherwise not compatible with
         * the interface method's declared return type as described above,
         * a {@code ClassCastException} will be thrown by the method
         * invocation on the proxy instance.
         *
         * @throws  Throwable the exception to throw from the method
         * invocation on the proxy instance.  The exception's type must be
         * assignable either to any of the exception types declared in the
         * {@code throws} clause of the interface method or to the
         * unchecked exception types {@code java.lang.RuntimeException}
         * or {@code java.lang.Error}.  If a checked exception is
         * thrown by this method that is not assignable to any of the
         * exception types declared in the {@code throws} clause of
         * the interface method, then an
         * {@link UndeclaredThrowableException} containing the
         * exception that was thrown by this method will be thrown by the
         * method invocation on the proxy instance.
         *
         * @see     UndeclaredThrowableException
         */
        
        @Override
        public Object invoke(Object proxy, Method m, Object[] args)    throws Throwable {
            //注入前的调用方法
            beforeMethod(m);
            //注入
            m.invoke(target, args);
            return null;
        }
    }

    编写测试类:Index.java

    package com.bq;
    
    import java.lang.reflect.Proxy;
    
    public class Index {
    
        public static void main(String[] args) {
            // 创建委托和被委托类对象
            UserDAO userDAO = new UserDAOImpl();
            LogInterceptor li = new LogInterceptor();
            // 给委托者设置目标
            li.setTarget(userDAO);
            /*
             * 注意下面这个对象的生成过程,给出参数说明 第一个参数是ClassLoader,直接使用被委托类的ClassLoader即可
             * 第二个参数是被委托类的接口名称 第三个参数是委托对象
             * 
             * @param loader the class loader to define the proxy class
             * 
             * @param interfaces the list of interfaces for the proxy class to
             * implement
             * 
             * @param h the invocation handler to dispatch method invocations to
             * 
             * @return a proxy instance with the specified invocation handler of a
             * proxy class that is defined by the specified class loader and that
             * implements the specified interfaces
             */
    
            UserDAO userDAOProxy = (UserDAO) Proxy.newProxyInstance(userDAO
                    .getClass().getClassLoader(), userDAO.getClass()
                    .getInterfaces(), li);
            // 打印出对象的类名称
            System.out.println(userDAOProxy.getClass().getName());
    
            /*
             * 调用被委托的方法 他会先调用beforeMethod(Method m);
             */
    
            userDAOProxy.addUser();
        }
    
    }

    至于如果你的类没有实现接口,Spring也可以帮你生成一个代理

    它使用CGLIB,这个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。

    Hibernate用它来实现PO字节码的动态生成。

  • 相关阅读:
    document
    winform(公共控件)
    winform属性
    ADO.NET(查询、属性扩展)
    ADO.NET(完整修改和查询、实体类,数据访问类)
    ADO.NET基础(增删改查)
    面向对象(类库、委托)
    c#复习整理
    面向对象(多态)
    面向对象(封装、继承)
  • 原文地址:https://www.cnblogs.com/bq12345/p/3243179.html
Copyright © 2020-2023  润新知