简述 AOP 动态代理

一、AopAutoConfiguration 源码:

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration {

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
				matchIfMissing = false)
		static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		static class CglibAutoProxyConfiguration {

		}

	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
			matchIfMissing = true)
	static class ClassProxyingConfiguration {

		ClassProxyingConfiguration(BeanFactory beanFactory) {
			if (beanFactory instanceof BeanDefinitionRegistry) {
				BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
				AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
		}

	}

}
  1. CglibAutoProxyConfiguration 类 matchIfMissing = true,所以默认使用 cglib 动态代理
  2. application.properties 里配置如下:spring.aop.auto=false,整个 AOP 都不会生效了
  3. application.properties 里配置如下:spring.aop.proxy-target-class=false,使用 jdk 动态代理

JDK 动态代理的限制在于,它只能代理实现了接口的类,如果一个类没有实现任何接口,JDK 动态代理就无法代理它,这是因为 JDK 动态代理是基于接口的代理,它生成的代理对象会实现指定接口,然后通过该接口来调用被代理类的方法。

需要注意的是,如果接口有多个实现类,并且你使用 @Autowired 注解注入时, Spring 会抛出异常,因为它无法确定应该注入哪个实现类的代理对象,在这种情况下,你需要明确指定要注入的实现类,可以使用 @Qualifier 注解或者在实现类上使用 @Primary 注解来解决这个问题

二、不使用 springboot,手动写 JDK 动态代理案例

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

public interface MyInterface {
    void myMethod();
}

public class MyInterfaceImpl implements MyInterface {
    public void myMethod() {
        System.out.println("Real object's method is called.");
    }
}

public class MyInvocationHandler implements InvocationHandler {
    private MyInterface target;

    public MyInvocationHandler(MyInterface target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Proxy object's method is called before real object's method.");
        Object result = method.invoke(target, args);
        System.out.println("Proxy object's method is called after real object's method.");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        MyInterface realObject = new MyInterfaceImpl();
        MyInvocationHandler handler = new MyInvocationHandler(realObject);

        MyInterface proxyObject = (MyInterface) Proxy.newProxyInstance(
                MyInterface.class.getClassLoader(),
                new Class[]{MyInterface.class},
                handler
        );

        proxyObject.myMethod();
    }
}

在JDK动态代理中,代理对象实现了指定接口,并且在运行时动态生成代理实例。被代理的类必须实现至少一个接口,而代理对象会实现这个接口,并且在方法调用时会委托给InvocationHandler中的逻辑

在这个例子中,proxyObject是MyInterface接口的代理对象。代理对象实现了MyInterface接口,并且在invoke方法中执行了额外的逻辑。当proxyObject.myMethod()被调用时,代理对象会先执行invoke方法中的逻辑,然后再调用MyInterfaceImpl实现类的myMethod方法

三、不使用 springboot,手动写 CGLIB 动态代理案例

CGLIB(Code Generation Library)是一个功能强大的字节码生成库,它可以在运行时动态生成类的子类,常用于代理那些没有实现接口的类。以下是一个简单的CGLIB动态代理的使用案例:

  1. pom 文件
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

  1. 然后,考虑以下的被代理类 UserService:
public class UserService {
    public void saveUser() {
        System.out.println("Saving user...");
    }
}

  1. 现在,我们会使用CGLIB为它生成一个代理对象,并在方法调用前后添加额外的逻辑:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class UserServiceProxy implements MethodInterceptor {

    public Object createProxy(Object target) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("Before method execution");
        Object result = methodProxy.invokeSuper(proxy, args);
        System.out.println("After method execution");
        return result;
    }

    public static void main(String[] args) {
        UserServiceProxy userServiceProxy = new UserServiceProxy();
        UserService userServiceProxyInstance = (UserService) userServiceProxy.createProxy(new UserService());
        userServiceProxyInstance.saveUser();
    }
}

  1. 在上述代码中,MethodInterceptor 接口用于定义拦截器的逻辑。在 intercept
    方法中,我们在方法调用前后添加了额外的逻辑。Enhancer 类用于生成代理类,它设置了被代理类的父类和拦截器。createProxy
    方法接受一个目标对象,返回一个代理对象。

    运行上述代码会输出以下结果:

Before method execution
Saving user...
After method execution

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值