jdk的动态代理实现aop

目录

一、jdk的动态代理如何使用

二、实现简单的aop

(1)基于接口的实现

(2)基于注解的实现


一、jdk的动态代理如何使用

1. 需要动态代理的接口

package com.yihua.base.proxy.jdk.v1;

/**
 * 用户服务
 *
 * @author YiHua
 * @date 2022/4/12 14:38
 */
public interface UserService {

    /**
     * 新增用户
     *
     * @param username
     * @param password
     */
    void addUser(String username, String password);

}

2. 需要代理的实际对象

package com.yihua.base.proxy.jdk.v1;

/**
 * 用户服务
 *
 * @author YiHua
 * @date 2022/4/12 14:39
 */
public class UserServiceImpl implements UserService {

    @Override
    public void addUser(String username, String password) {
        System.out.println("传入参数为 username: " + username + " password: " + password);
    }

}

3. 实现处理器接口

package com.yihua.base.proxy.jdk.v1;

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

/**
 * 代理类
 * jdk的动态代理:定义一个实现 InvocationHandler 接口的代理类,重写 invoke () 方法,且添加 getProxy () 方法。
 *
 * @author YiHua
 * @date 2022/4/12 14:41
 */
public class JdkProxy implements InvocationHandler {

    // 定义被代理的类,也就是需要代理的目标对象
    private Object targetObject;

    /**
     * 无参构造
     */
    public JdkProxy() {

    }

    /**
     * 定义获取代理对象方法
     *
     * @param targetObject 需要代理的对象
     * @return 代理对象
     */
    public Object getProxyObject(Object targetObject) {
        // 给被代理的对象服务
        this.targetObject = targetObject;

        // 获取到被代理对象的实例
        Class<?> c = targetObject.getClass();

        // 通过反射获取,被代理对象的:类加载器、这个类实现的接口
        ClassLoader classLoader = c.getClassLoader();
        Class<?>[] interfaces = c.getInterfaces();

        // 通过反射类提供的newProxyInstance方法,创建提供的代理类实例
        return Proxy.newProxyInstance(classLoader, interfaces, this);
    }

    /**
     * 处理代理实例上的方法调用并返回结果。当在与其关联的代理实例上调用方法时,将在调用处理程序上调用此方法
     *
     * @param proxy  调用该方法的代理实例
     * @param method Method实例对应于代理实例上调用的接口方法
     * @param args   一个对象数组,其中包含在代理实例上的方法调用中传递的参数值,如果接口方法不接受任何参数,则null
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK动态代理,监听开始!");
        System.out.println("动态代理增强原来的方法>>>>>>>>>>>>>>>>>>>>>>");
        String username = (String) args[0];
        String password = (String) args[1];
        // 增强信息:只能添加指定用户"admin、123"
        System.out.println("开始权限校验");
        if (!(username.equals("admin") && password.equals("123"))) {
            System.out.println("新增用户信息不合法");
            return null;
        }
        System.out.println("权限校验成功,可以新增");
        System.out.println("动态代理增强结束<<<<<<<<<<<<<<<<<<<<<<<<");
        // 这个是真正的执行方法,这个method是反射获取的,直接使用它的invoke方法执行
        Object result = method.invoke(targetObject, args);
        System.out.println("JDK动态代理,监听结束!");
        return result;
    }
}

4. 测试类

package com.yihua.base.proxy.jdk.v1;

/**
 * 测试基于实现类的方式
 *
 * @author YiHua
 * @date 2022/4/12 14:38
 */
public class JdkProxyByClassTest {
    public static void main(String[] args) {

        // 实例化JDKProxy对象
        JdkProxy jdkProxy = new JdkProxy();

        // 目标对象(被代理的对象)
        UserServiceImpl userServiceImpl = new UserServiceImpl();

        // 获取到代理对象
        UserService userService = (UserService) jdkProxy.getProxyObject(userServiceImpl);
        // fixme 这里代理类无法强转为被代理对象的实现类,否则会转换失败,这里也印证jdk的代理只能代理实现了接口的对象
        // UserServiceImpl userService = (UserServiceImpl) jdkProxy.getProxyObject(userServiceImpl);

        // 执行新增方法
        userService.addUser("admin", "123");

    }
}

二、实现简单的aop

(1)基于接口的实现

1. 需要动态代理的接口

package com.yihua.base.proxy.jdk.v2;

/**
 * 订单服务
 *
 * @author YiHua
 * @date 2021/12/7 11:33 上午
 */
public interface OrderService {

    /**
     * 支付
     */
    void pay() throws InterruptedException;

    /**
     * 展示
     */
    void show();

}

2. 需要代理的实际对象

package com.yihua.base.proxy.jdk.v2;

/**
 * 订单服务
 *
 * @author YiHua
 * @date 2021/12/7 11:33 上午
 */
public class OrderServiceImpl implements OrderService {

    int status = 0;

    /**
     * 下单
     */
    @Override
    public void pay() throws InterruptedException {
        Thread.sleep(50);
        this.status = 1;
        System.out.println("pay success, pay status " + this.status);
    }

    /**
     * 展示
     */
    @Override
    public void show() {
        int a = 1 + 2;
        System.out.println("order status " + this.status);
    }

}

3. 动态代理接口

package com.yihua.base.proxy.jdk.v2;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;

/**
 * 动态代理接口
 *
 * @author YiHua
 * @date 2021/12/8 12:24 上午
 */
public interface Aspect {

    /**
     * 在...之前
     */
    void before();

    /**
     * 在...之后
     */
    void after();

    /**
     * 创建一个代理
     *
     * @param tClass  需要代理的对象
     * @param aspects 实现这个接口的对象的项目路径
     * @param <T>
     */
    static <T> T createProxy(Class<T> tClass, String... aspects) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        // 存储所有实现了该接口的,的实例对象
        ArrayList<Aspect> list = new ArrayList<>();

        // 遍历传递进来的路径,通过反射获取实例对象
        for (String aspect : aspects) {
            Class<?> aClass = Class.forName(aspect);
            Aspect asp = (Aspect) aClass.getConstructor().newInstance();
            list.add(asp);
        }

        // 获取到被代理对象的实例
        T instance = tClass.getConstructor().newInstance();
        ClassLoader classLoader = tClass.getClassLoader();
        Class<?>[] interfaces = tClass.getInterfaces();

        // 生成一个代理对象
        return (T) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                for (Aspect aspect : list) {
                    aspect.before();
                }
                Object invoke = method.invoke(instance,args);
                for (Aspect aspect : list) {
                    aspect.after();
                }
                return invoke;
            }
        });
    }
}

4. 测试类

package com.yihua.base.proxy.jdk.v2;


import java.lang.reflect.InvocationTargetException;

/**
 * 测试基于接口的实现方式
 *
 * @author YiHua
 * @date 2021/12/8 1:00 上午
 */
public class JdkProxyByInterfaceTest {

    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, InterruptedException {

        // 区别于通过实现类的实现方式,通过接口的静态方法直接获取代理对象
        OrderService orderService = Aspect.createProxy(OrderServiceImpl.class, "com.yihua.springboot.aop.proxy.jdk.interf.InterfaceTimeAspect");

        orderService.pay();

        orderService.show();

    }
}

(2)基于注解的实现

 1. 需要动态代理的接口

package com.yihua.base.proxy.jdk.v2;

/**
 * 订单服务
 *
 * @author YiHua
 * @date 2021/12/7 11:33 上午
 */
public interface OrderService {

    /**
     * 支付
     */
    void pay() throws InterruptedException;

    /**
     * 展示
     */
    void show();

}

2. 需要代理的实际对象(注意这里使用的自定义的注解)

package com.yihua.base.proxy.jdk.v2;

/**
 * 订单服务
 *
 * @author YiHua
 * @date 2021/12/7 11:33 上午
 */
@Aspect(type = InterfaceTimeAspect.class)
public class OrderServiceImpl implements OrderService {

    int status = 0;

    /**
     * 下单
     */
    @Override
    public void pay() throws InterruptedException {
        Thread.sleep(50);
        this.status = 1;
        System.out.println("pay success, pay status " + this.status);
    }

    /**
     * 展示
     */
    @Override
    public void show() {
        int a = 1 + 2;
        System.out.println("order status " + this.status);
    }

}

3. 定义增强的接口

/**
 * 定义增强的相关方法的接口
 *
 * @author YiHua
 * @date 2021/12/8 11:41 上午
 */
public interface IAspect {

    void before();

    void after();

}

4. 定义实现类,具体的增强逻辑

package com.yihua.base.proxy.jdk.v3;

import com.yihua.base.proxy.jdk.v2.Aspect;

/**
 * 实现增强的相关方,定义具体地增强逻辑
 *
 * @author YiHua
 * @date 2021/12/8 12:31 上午
 */
public class InterfaceTimeAspect implements IAspect {

    long start;

    @Override
    public void before() {
        this.start = System.currentTimeMillis();
    }

    @Override
    public void after() {
        long resTime = System.currentTimeMillis() - this.start;
        System.out.format("time resTime: %dms\n", resTime);
    }
}

5. 切面注解

package com.yihua.base.proxy.jdk.v3;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 切面注解
 *
 * @author YiHua
 * @date 2021/12/8 11:38 上午
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect {

    Class<?> type();

}

6. 定义代理工厂

package com.yihua.base.proxy.jdk.v3;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedList;

/**
 * 代理工厂
 *
 * @author YiHua
 * @date 2021/12/8 11:45 上午
 */
public class ObjectFactory {

    public static <T> T newInstance(Class<T> tClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 获取传入的类所有的注解,例如传入了'orderServiceImpl'
        Annotation[] annotations = tClass.getAnnotations();

        // 定义一个list装载这些'切面'
        LinkedList<IAspect> iAspects = new LinkedList<>();

        // 遍历所有的注解,找出'Aspect'注解,这个类似于'切点'
        // 将这个引用的类创建实例,然后保存起来,后续会通过这些实例去执行,切面中的方法
        for (Annotation annotation : annotations) {
            if (annotation instanceof Aspect) {
                Class<?> type = ((Aspect) annotation).type();
                IAspect iAspect = (IAspect) (type.getConstructor().newInstance());
                iAspects.push(iAspect);
            }
        }

        // 这个实例就是用来执行真正的主方法,使用传入的类创建实例,相当于 new ,例如 OrderServiceImpl o = new OrderServiceImpl;
        T instance = tClass.getConstructor().newInstance();
        ClassLoader classLoader = tClass.getClassLoader();
        Class<?>[] interfaces = tClass.getInterfaces();

        // 返回jdk的动态代理对象,切面方法会在本类中执行,实际业务会在外面显示调用,在内部通过反射的方式调用
        return (T) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                iAspects.forEach(IAspect::after);
                Object invoke = method.invoke(instance, args);
                iAspects.forEach(IAspect::before);
                return invoke;
            }
        });
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值