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字节码的动态生成。

原文地址:https://www.cnblogs.com/bq12345/p/3243179.html