静态代理、动态代理、cglib代理及简单案例、常见相关的运用

静态代理、动态代理和CGLIB代理都是常见的代理模式,用于在对象之间添加额外的功能或控制访问。

@EnableTransactionManagement(proxyTargetClass = true) 的 作用

当将 proxyTargetClass 设置为 true 时,将使用基于CGLIB的代理。这意味着Spring会在运行时创建目标类的子类,并将其用作代理。CGLIB代理可以用于没有实现任何接口的类。
另一方面,当将 proxyTargetClass 设置为 false 或未指定时,将使用基于JDK的动态代理。JDK动态代理只能用于接口,而不能用于类。
因此,区别在于Spring用于事务方法的代理机制。如果将 proxyTargetClass 设置为 true ,将使用基于CGLIB的代理,即使目标类没有实现任何接口,也可以对事务方法进行代理。如果将 proxyTargetClass 设置为 false 或省略该属性,则将使用基于JDK的动态代理,对于事务方法进行代理,目标类必须实现至少一个接口。
在大多数情况下,您可以使用默认行为,无需指定 proxyTargetClass 。

模拟mybatis给dao生成代理类

jdk代理直接对接口进行代理处理,获取方法注解信息进行中间加工,而不是对接口实现类的方法进行处理

SysUserDao

public interface SysUserDao {

    @Select("select * from sys_user where id = #{id}")
    SysUser getById(@Param("id") Long id);

}

@Data
public class SysUser implements Serializable {

    private Long id;

    private String name;

    private Integer age;

}

代理处理

public class DaoProxy implements InvocationHandler {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Select select = method.getAnnotation(Select.class);
        String sql = select.value();
        System.out.println("获取sql: " + sql);
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        int index = 0;
        for (Annotation[] annotation : parameterAnnotations) {
            for (Annotation paramAnno : annotation) {
                if (paramAnno instanceof Param) {
                    String value = ((Param) paramAnno).value();
                    System.out.println("获取参数: " + value + " 值: " + args[index]);
                }
            }
            index++;
        }
        Class<?> returnType = method.getReturnType();
        System.out.println("获取返回值类型: " + returnType.getName());
        return returnType.newInstance();

    }

}

public class DaoFactory {

    public <T> T getData(Class<T> tClass) {
        return (T) Proxy.newProxyInstance(tClass.getClassLoader(), new Class[]{tClass}, new DaoProxy());
    }

}

test

public class TestProxy {

    @Test
    public void test() {

        DaoFactory factory = new DaoFactory();
        SysUserDao sysUserDao = factory.getData(SysUserDao.class);
        Assert.assertNotNull(sysUserDao);
        Assert.assertTrue(sysUserDao instanceof Proxy);
        SysUser sysUser = sysUserDao.getById(1L);
        Assert.assertNotNull(sysUser);

    }
}

静态代理

静态代理是在编译时创建代理类的一种代理形式。代理类和目标类实现相同的接口,并在代理类中调用目标类的方法,可以在方法前后添加额外的逻辑。
RealSubject 是目标类, ProxySubject 是代理类,它实现了相同的接口 Subject 。在 ProxySubject 的 doSomething 方法中,可以在调用 RealSubject 的方法前后添加额外的逻辑。

public interface Subject {
    void doSomething();
}

public class RealSubject implements Subject {
    public void doSomething() {
        System.out.println("RealSubject: doing something.");
    }
}

public class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    public void doSomething() {
        System.out.println("ProxySubject: before doing something.");
        realSubject.doSomething();
        System.out.println("ProxySubject: after doing something.");
    }
}

// 使用示例
RealSubject realSubject = new RealSubject();
ProxySubject proxySubject = new ProxySubject(realSubject);
proxySubject.doSomething();

动态代理

动态代理是在运行时创建代理对象的一种代理形式。代理类不需要实现特定的接口,而是通过 java.lang.reflect.Proxy 类或第三方库(如CGLIB)来动态生成代理对象。
DynamicProxy 实现了 InvocationHandler 接口,并在 invoke 方法中添加了额外的逻辑。通过 Proxy.newProxyInstance 方法创建了动态代理对象,该对象可以调用目标对象的方法,并在方法前后添加额外的逻辑。

public interface Subject {
    void doSomething();
}

public class RealSubject implements Subject {
    public void doSomething() {
        System.out.println("RealSubject: doing something.");
    }
}

public class DynamicProxy implements InvocationHandler {
    private Object target;

    public DynamicProxy(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("DynamicProxy: before doing something.");
        Object result = method.invoke(target, args);
        System.out.println("DynamicProxy: after doing something.");
        return result;
    }
}

// 使用示例
RealSubject realSubject = new RealSubject();
Subject proxySubject = (Subject) Proxy.newProxyInstance(
        Subject.class.getClassLoader(),
        new Class[]{Subject.class},
        new DynamicProxy(realSubject)
);
proxySubject.doSomething();

CGLIB代理

CGLIB(Code Generation Library)是一个基于字节码生成的第三方库,用于创建动态代理对象。CGLIB代理不需要目标类实现接口,而是通过继承目标类并重写方法来创建代理对象。
CglibProxy 实现了 MethodInterceptor 接口,并在 intercept 方法中添加了额外的逻辑。通过 Enhancer 类创建了CGLIB代理对象,该对象继承了目标类 RealSubject ,并在方法调用时拦截并添加额外的逻辑。

public class RealSubject {
    public void doSomething() {
        System.out.println("RealSubject: doing something.");
    }
}

public class CglibProxy implements MethodInterceptor {
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("CglibProxy: before doing something.");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("CglibProxy: after doing something.");
        return result;
    }
}

// 使用示例
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new CglibProxy());

RealSubject proxySubject = (RealSubject) enhancer.create();
proxySubject.doSomething();
posted @ 2023-08-23 18:47  linzm14  阅读(35)  评论(0编辑  收藏  举报