Java反射机制与SpringAOP(动态代理)

Java反射机制

运行状态中,对于任意一个类能获取与调用这个类的属性、方法。

1.获取Class

Class userClass1 = new USer().getClass();
Class userClass2 = User.class;
Class userClass3 = Class.forName("com.jun.entity.User");

2.Class重要模块

    // 获取Class
    Class userClass =Class.forName("com.jun.entity.User");
    //调用无参数构造方法.
    Object = userClass.newInstance();
    // 获取Class
    Class userClass = User.class;
    // 获取构造方法
    Constructor[] constructor = userClass.getConstructors();
    // 获取属性
    Field[] fields = userClass.getDeclaredFields();
    // 获取方法
    Method[] methods = userClass.getMethods();

3.Class类、Field类、Method类、Constructor类


Class类方法
public T newInstance()	创建对象
public String getName()	返回完整类名带包名
public String getSimpleName()	返回类名
public Field[] getFields()	返回类中public修饰的属性
public Field[] getDeclaredFields()	返回类中所有的属性
public Field getDeclaredField(String name)	根据属性名name获取指定的属性
public native int getModifiers()	获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】
public Method[] getDeclaredMethods()	返回类中所有的实例方法
public Method getDeclaredMethod(String name, Class<?>… parameterTypes)	根据方法名name和方法形参获取指定方法
public Constructor<?>[] getDeclaredConstructors()	返回类中所有的构造方法
public Constructor getDeclaredConstructor(Class<?>… parameterTypes)	根据方法形参获取指定的构造方法
public native Class<? super T> getSuperclass()	返回调用类的父类
public Class<?>[] getInterfaces()	返回调用类实现的接口集合


Field类方法
public String getName()	返回属性名
public int getModifiers()	获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】
public Class<?> getType()	以Class类型,返回属性类型【一般配合Class类的getSimpleName()方法使用】
public void set(Object obj, Object value)	设置属性值
public Object get(Object obj)	读取属性值


Method类方法
public String getName()	返回方法名
public int getModifiers()	获取方法的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】
public Class<?> getReturnType()	以Class类型,返回方法类型【一般配合Class类的getSimpleName()方法使用】
public Class<?>[] getParameterTypes()	返回方法的修饰符列表(一个方法的参数可能会有多个。)【结果集一般配合Class类的getSimpleName()方法使用】
public Object invoke(Object obj, Object… args)	调用方法


Constructor类方法
public String getName()	返回构造方法名
public int getModifiers()	获取构造方法的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】
public Class<?>[] getParameterTypes()	返回构造方法的修饰符列表(一个方法的参数可能会有多个。)【结果集一般配合Class类的getSimpleName()方法使用】
public T newInstance(Object … initargs)	创建对象【参数为创建对象的数据】

动态代理

一、JDK动态代理

JDK动态代理只支持接口代理。
InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起,
Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。

/**
 * 目标接口
 */
public interface JunService {
    public void testJdkProxy(int topicId);
}
/**
 * 目标接口实现
 */
public class JunServiceImple implements JunService {
    @Override
    public void testJdkProxy(int topicId) {
        System.out.println("");
        System.out.println("----------逻辑实现: "+topicId);
        System.out.println("");
    }
}

/**
 * 代理
 */
public class JunJdkHandle implements InvocationHandler {

    // 目标(被代理的接口)
    private Object object;

    // 指定目标
    public JunJdkHandle(Object object) {
        this.object=object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //业务逻辑代码
        System.out.println("---JDK代理开始---");
        System.out.println("---method: "+method.toString());
        System.out.println("---args: "+args.toString());
        //通过Java反射机制调用业务类的目标方法
        Object obj = method.invoke(object, args);
        //业务逻辑代码
        System.out.println("---JDK代理结束---");
        return obj;
    }
}


public class Test01 {
    public static void main(String[] args) {
        // 创建被代理的 目标接口
        JunService target = new JunServiceImple();
        // 将目标接口 传入 代理
        JunJdkHandle junhandle = new JunJdkHandle(target);
        // 接口创建代理实例。
        // 参数: 类加载器、目标接口、代理类
        JunService junService = (JunService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                junhandle);
        // 调用接口
        junService.testJdkProxy(9999999);
    }
}

结果:
---JDK代理开始---
---method: public abstract void com.south.aop.jdk.JunService.testJdkProxy(int)
---args: [Ljava.lang.Object;@65b54208

----------逻辑实现: 9999999

---JDK代理结束---

二、Cglibd动态代理

在运行时动态的生成指定类的子类对象,覆盖其中特定方法并添加增强代码,从而实现AOP。
通过继承方式做动态代理,如果某个类被标记为final,是无法用CGLIB做动态代理的。

1.引入依赖

        <!-- cglib依赖 -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.1</version>
        </dependency>

2.代码实现

/**
 * 接口(父类)
 */
public interface JunService {
    public void testCglibProxy(int topicId);
}

/**
 * 实现(子类)
 */
public class JunServiceImple implements JunService {
    @Override
    public void testCglibProxy(int topicId) {
        System.out.println("");
        System.out.println("------------------实际实现方法: "+topicId);
        System.out.println("");
    }
}


import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
/**
 * 代理类
 */
public class JunCglibProxy implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

    //
    public Object getProxy(Class clazz) {
        // 设置需要创建子类的类
        enhancer.setSuperclass(clazz);
        //
        enhancer.setCallback(this);
        // 通过字节码技术动态创建子类实例
        return enhancer.create();
    }

    //拦截所有父类方法
    // Object目标类实例, Method目标类方法的反射对象, Object[]方法的动态入参, MethodProxy代理类
    @Override
    public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy proxy) throws Throwable {
        System.out.println("CGLib动态代理开始");
        System.out.println("------参数 arg1: "+arg1.toString());
        // 通过代理类调用父类的方法
        Object result = proxy.invokeSuper(arg0, arg2);
        System.out.println("CGLib动态代理结束");
        return result;
    }
}


import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
/**
 * 代理类
 */
public class JunCglibProxy implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

    //
    public Object getProxy(Class clazz) {
        // 设置需要创建子类的类
        enhancer.setSuperclass(clazz);
        //
        enhancer.setCallback(this);
        // 通过字节码技术动态创建子类实例
        return enhancer.create();
    }

    //拦截所有父类方法
    // Object目标类实例, Method目标类方法的反射对象, Object[]方法的动态入参, MethodProxy代理类
    @Override
    public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy proxy) throws Throwable {
        System.out.println("CGLib动态代理开始");
        System.out.println("------参数 arg1: "+arg1.toString());
        // 通过代理类调用父类的方法
        Object result = proxy.invokeSuper(arg0, arg2);
        System.out.println("CGLib动态代理结束");
        return result;
    }
}

public class Tste02 {
    public static void main(String [] args) {
         // 创建代理类
         JunCglibProxy junCglibProxy = new JunCglibProxy();
         // 参数: 监视子类
         JunService form = (JunService) junCglibProxy.getProxy(JunServiceImple.class);
         form.testCglibProxy(99999);
    }
}


结果:
CGLib动态代理开始
------参数 arg1: public void com.south.aop.cglib.JunServiceImple.testCglibProxy(int)

------------------实际实现方法: 99999

CGLib动态代理结束

AOP的应用

记录日志(调用方法后记录日志)
监控性能(统计方法运行时间)
权限控制(调用方法前校验是否有权限)
事务管理(调用方法前开启事务,调用方法后提交关闭事务)
缓存优化(第一次调用查询数据库,将查询结果放入内存对象,第二次调用,直接从内存对象返回,不需要查询数据库)

1.引入依赖

        <!-- AOP依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.7.8</version>
        </dependency>

2.代码实现

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.json.JSONObject;
import org.springframework.stereotype.Component;


@Aspect
@Component
public class JunAspect {

    // 监听方法
    @Pointcut("execution(* com.south.controller.*.*(..))")
    public void pointCutExecution() {

    }

    // 监听注解 @PermissionsAnnotation
    @Pointcut("@annotation(com.south.controller.*.PermissionsAnnotation)")
    private void pointCutAnnotation() {

    }

    @Around("pointCutAnnotation()")
    public Object pointCutExecution(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("===================开始增强处理===================");
        //获取请求参数,详见接口类
        Object[] objects = joinPoint.getArgs();
        Long id = ((JSONObject) objects[0]).getLong("id");
        String name = ((JSONObject) objects[0]).getString("name");
        System.out.println("id1->>>>>>>>>>>>>>>>>>>>>>" + id);
        System.out.println("name1->>>>>>>>>>>>>>>>>>>>>>" + name);
        // 修改入参
        JSONObject object = new JSONObject();
        object.put("id", 8);
        object.put("name", "lisi");
        objects[0] = object;
        // 将修改后的参数传入
        return joinPoint.proceed(objects);
    }

    /**
     * 在上面定义的切面方法之前执行该方法
     */
    @Before("pointCutExecution()")
    public void doBefore(JoinPoint joinPoint) {
        // 获取签名
        Signature signature = joinPoint.getSignature();
        // 获取切入的包名
        String declaringTypeName = signature.getDeclaringTypeName();
        // 获取即将执行的方法名
        String funcName = signature.getName();
    }

    /**
     * 在上面定义的切面方法之后执行该方法
     */
    @After("pointCutExecution()")
    public void doAfter(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        String method = signature.getName();
    }

    /**
     * 在上面定义的切面方法返回后执行该方法,可以捕获返回对象或者对返回对象进行增强。
     */
    @AfterReturning(pointcut = "pointCutExecution()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
        Signature signature = joinPoint.getSignature();
        String classMethod = signature.getName();
    }
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值