Java高级特性之动态代理

Java高级特性之动态代理

学习之前首先介绍一下代理模式

这里拿手机销售来说、比方说三星厂商生产出了手机、之后需要经过销售、于是交给了厂商B来销售、所以B是一个代理销售商、但是厂商B在销售之前之后会做其他的动作。因此不仅仅是简单的进行销售。

流程图:

在这里插入图片描述

这里在模版上有点类似装饰者式,但是这里是不一样的。装饰者更强调行为、而代理模式更强调对象本身。

静态代理

1、被代理对象

/**
 * @Author Zzneko
 * @Date 2022/9/9 16:07
 **/
public class ProxyObj {

    public void sayHello(){
        System.out.println("hello");
    }
}

2、代理对象

package proxy.simpleProxy;

/**
 * 代理对象
 * */
public class Proxy {

    private ProxyObj proxyObj;

    public Proxy(ProxyObj proxyObj) {
        this.proxyObj = proxyObj;
    }

    /**
     * 代理方法
     */
    public void methodEnhance(){
        System.out.println("before say hello");
        proxyObj.sayHello();
        System.out.println("after say hello");
    }

}

3、测试

/**
 * @Author Zzneko
 * @Date 2022/9/9 16:10
 **/
public class ProgramEntering {
    public static void main(String[] args) {
        ProxyObj proxyObj = new ProxyObj();
        Proxy proxy = new Proxy(proxyObj);
        proxy.methodEnhance();
    }
}

静态代理很简单这里就不做过多讲述了

动态代理

动态代理有两种

一、JDK

1、被代理的类。

package proxy.jdk;

/**
 * @Author Zzneko
 * @Date 2022/9/7 12:50
 * 被代理类
 **/
public class ServiceImp implements IService{
    @Override
    public void sayHello() {
        System.out.println("hello");
    }

    @Override
    public void fly() {
        System.out.println("i am flying");
    }
}

//-----------实现的接口
package proxy.jdk;


/**
 * 代理接口
 */
public interface IService {
    void sayHello();

    void fly();
}

2、代理类

package proxy.jdk;

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

/**
 * @Author Zzneko
 * @Date 2022/9/7 12:50
 * 代理类
 **/
public class SimpleInvocationHandler implements InvocationHandler {
    //被代理的对象
    private Object realObject;

    public SimpleInvocationHandler(Object object) {
        this.realObject = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("entering"+method.getName());
        Object result = method.invoke(realObject, args);
        System.out.println("leaving"+method.getName());
        return result;
    }
}

3、测试类

public class SimpleJDKDynamicProxyDemo {
    public static void main(String[] args) {
        IService service = new ServiceImp();
        IService iService = (IService) Proxy.newProxyInstance(IService.class.getClassLoader(), new Class<?>[]{
                IService.class
        }, new SimpleInvocationHandler(service));
        service.sayHello();
        service.fly();
        System.out.println("代理之后");
        iService.fly();
        iService.sayHello();
    }
}

解读:

1、现在我们的创建的对象

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

这个方法创建、他拥有三个参数

1)loader标识类加载器

2)标识代理类要实现的接口列表,是一个数组,元素的接口类型只能是接口,不能是普通的类。

3)h的类型是InvocationHandler,它是一个接口,也定义在反射包中。它定义了一个方法inboke,对代理接口所有方法的调用都会转给该方法。

该方法返回的Object可以强制转换interfaces中的某个接口的类型。值得注意的是它不能强制换花为某个类类型。

二、CGLib

1、被代理对象

/**
 * @Author Zzneko
 * @Date 2022/9/7 13:18
 **/
public class RealService {
    public void sayHello(){
        System.out.println("hello world");
    }
}

2、代理对象

/**
 * @Author Zzneko
 * @Date 2022/9/7 13:18
 **/
public class SimpleInterceptor implements MethodInterceptor {
    //VM   Jdk8之后 启动参数记得加上 --add-opens java.base/java.lang=ALL-UNNAMED
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("entering\t"+method.getName());
        Object invoke = methodProxy.invokeSuper(o, objects);
        System.out.println("leaving\t"+method.getName());
        return invoke;
    }
    public static<T> T getProxy(Class<T> cls){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(cls);
        enhancer.setCallback(new SimpleInterceptor());
        return (T) enhancer.create();
    }
}

3、测试

/**
 * @Author Zzneko
 * @Date 2022/9/7 13:18
 **/
public class SimpleCGLibDemo {
    public static void main(String[] args) {
        RealService realService = new RealService();
        realService.sayHello();
        System.out.println("代理类的方法");
        RealService proxy = SimpleInterceptor.getProxy(RealService.class);
        proxy.sayHello();
    }
}

总结:

JDK中的代理面向的是一组接口、其背后不一定真正有被代理的对象,也可能有多个实际对象

cglib代理的是一个具体的类。他动态的创建类一个新类、继承该类、重写了其方法

动态代理应用-AOP

1、定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect{
    Class<?>[] value();
}

2、定义切面类

/**
 * @Author Zzneko
 * @Date 2022/9/9 17:00
 **/
@Aspect(ServiceB.class)
public class ExceptionAspect {
    public static void exception(Object object,
                                 Method method,
                                 Object[] args,
                                 Throwable e) {
        System.err.println("exception when calling: " + method.getName()
                + "," + Arrays.toString(args));
    }
}
package aop.Aspect;

import Annotaion.diInject.ServiceA;
import Annotaion.diInject.ServiceB;
import aop.annotaion.Aspect;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @Author Zzneko
 * @Date 2022/9/9 17:00
 **/
@Aspect({ServiceB.class, ServiceA.class})
public class ServiceLogAspect {
    public static void before(Object object,
                              Method method,
                              Object[] args) {
        System.out.println(
                "entering " + method.getDeclaringClass().getSimpleName()
                + "::" + method.getName() + ", args: " + Arrays.toString(args)
        );
    }

    public static void after(Object object,
                             Method method,
                             Object[] args,
                             Object result) {
        System.out.println(
                "leaving " + method.getDeclaringClass().getSimpleName()
                + "::" + method.getName() + ", result: " + result
        );
    }
}

3、定义容器

/**
 * @Author Zzneko
 * @Date 2022/9/9 17:04
 **/
public class CGLibContainer {
    /**
     * 容器初始化分析所有带@Aspect的类,分析每个类的方法、前后需要调用那些方法。
     * */
    private static Map<Class<?>,Map<InterceptPoint, List<Method>>>  interceptMethodsMap =new HashMap();

    static Class<?>[] aspects = new Class<?>[] { ServiceLogAspect.class, ExceptionAspect.class };

    static {
        init();
    }

    private static void init(){
        for (Class<?> cls : aspects) {
            /**
             * :用于获得切面的注解。
             *   以及根据方法名、来获取方法。
             * */
            Aspect aspect = cls.getAnnotation(Aspect.class);
            if (aspect!=null) {
                Method before = getMethod(cls, "before", new Class<?>[]{  Object.class,
                                   Method.class,
                                   Object[].class
                                }
                );
                Method after = getMethod(cls, "after", new Class<?>[]{  Object.class,
                                Method.class,
                                Object[].class
                        }
                );
                Method exception = getMethod(cls,"exception",new Class<?>[]{Object.class,Method.class,Object[].class,Throwable.class});
                //切面中面向的类。
                Class<?>[] value = aspect.value();
                for (Class<?> aClass : value) {
                    //对切面的对象生成代理类。
                    addInterceptMethod(aClass,InterceptPoint.BEFORE,before);
                    addInterceptMethod(aClass,InterceptPoint.AFTER,after);
                    addInterceptMethod(aClass,InterceptPoint.EXCEPTION,exception);
                }
            }
        }
    }

    /***
     * 添加被代理的类、以及被增强的方法。
     * @param cls 被代理类。
     * @param point 切点
     * @param method 被代理方法
     */
    private static void addInterceptMethod(Class<?> cls, InterceptPoint point, Method method) {
        if (method==null) {
            return;
        }
        /**
         * 获得当前切面的所有方法
         */
        Map<InterceptPoint, List<Method>> map = interceptMethodsMap.get(cls);
        if (map==null) {
            map=new HashMap<>();
            interceptMethodsMap.put(cls,map);
        }
        List<Method> methods = map.get(point);
        if (methods==null) {
            methods=new ArrayList<>();
            map.put(point,methods);
        }
        methods.add(method);
    }

    /**
     * 创建代理类
     * @param cls
     * @param <T>
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private static <T> T createInstance(Class<T> cls) throws InstantiationException, IllegalAccessException {
        //如果容器有当前类对象、则直接返回否则进行代理创建。
        if (!interceptMethodsMap.containsKey(cls)) {
            return (T) cls.newInstance();
        }
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(cls);
        enhancer.setCallback(new AspectInterceptor());
        return (T) enhancer.create();
    }

    /**
     * 代理生成
     */
    static class AspectInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object object, Method method,
                                Object[] args, MethodProxy proxy) throws Throwable {
            //执行before方法
            List<Method> beforeMethods = getInterceptMethods(
                    object.getClass().getSuperclass(), InterceptPoint.BEFORE);
            for (Method m : beforeMethods) {
                m.invoke(null, new Object[] { object, method, args });
            }

            try {
                // 调用原始方法
                Object result = proxy.invokeSuper(object, args);

                // 执行after方法
                List<Method> afterMethods = getInterceptMethods(
                        object.getClass().getSuperclass(), InterceptPoint.AFTER);
                for (Method m : afterMethods) {
                    m.invoke(null, new Object[] { object, method, args, result });
                }
                return result;
            } catch (Throwable e) {
                //执行exception方法
                List<Method> exceptionMethods = getInterceptMethods(
                        object.getClass().getSuperclass(), InterceptPoint.EXCEPTION);
                for (Method m : exceptionMethods) {
                    m.invoke(null, new Object[] { object, method, args, e });
                }
                throw e;
            }
        }
    }

    private static Method getMethod(Class<?> cls, String name, Class<?>[] paramTypes) {
        try {
            return cls.getMethod(name, paramTypes);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

    static List<Method> getInterceptMethods(Class<?> cls, InterceptPoint point) {
        Map<InterceptPoint, List<Method>> map = interceptMethodsMap.get(cls);
        if (map == null) {
            return Collections.emptyList();
        }
        List<Method> methods = map.get(point);
        if (methods == null) {
            return Collections.emptyList();
        }
        return methods;
    }

    /**
     * 属性注入以及容器获取
     * @param cls
     * @param <T>
     * @return
     */
    public static <T> T getInstance(Class<T> cls) {
        try {
            T obj = createInstance(cls);
            Field[] fields = cls.getDeclaredFields();
            for (Field f : fields) {
                if (f.isAnnotationPresent(SimpleInject.class)) {
                    if (!f.isAccessible()) {
                        f.setAccessible(true);
                    }
                    Class<?> fieldCls = f.getType();
                    f.set(obj, getInstance(fieldCls));
                }
            }
            return obj;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

4、定义被具体的service

/**
 * @Author Zzneko
 * @Date 2022/9/9 17:00
 **/
public class ServiceA {
    @SimpleInject
    ServiceB b;

    public void callB(){
        b.action();
    }

    public ServiceB getB() {
        return b;
    }
}
/**
 * @Author Zzneko
 * @Date 2022/9/9 17:01
 **/
public class ServiceB {
    public void action(){
        System.out.println("I'm B");
    }
}

切面常量

public enum InterceptPoint {
    BEFORE,AFTER,EXCEPTION
}

测试

/**
 * @Author Zzneko
 * @Date 2022/9/9 17:04
 **/
public class ProgramEntering {
    public static void main(String[] args) {
        ServiceA a = CGLibContainer.getInstance(ServiceA.class);
        a.callB();
    }
}

结果

entering ServiceA::callB, args: []
entering ServiceB::action, args: []
I’m B
leaving ServiceB::action, result: null
leaving ServiceA::callB, result: null

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值