hutool源码学习第一天-aop
普通实现方式
1. JDK 动态代理
JDK 动态代理是基于 Java 反射机制的一种代理方式,它允许在运行时动态创建实现了某些接口的代理对象。它的主要特点是:
- 要求:被代理的类必须实现一个或多个接口。
- 代理类:由
java.lang.reflect.Proxy
类动态生成。 - 核心接口:
InvocationHandler
。
详细实现步骤:
-
定义接口:创建一个接口,规定要代理的方法。
public interface HelloService { void sayHello(); }
-
实现接口:创建一个实现接口的具体类。
public class HelloServiceImpl implements HelloService { @Override public void sayHello() { System.out.println("Hello, world!"); } }
-
创建 InvocationHandler:实现
InvocationHandler
接口,以便在方法调用时插入自定义逻辑。import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before method: " + method.getName()); Object result = method.invoke(target, args); System.out.println("After method: " + method.getName()); return result; } }
-
生成代理对象:使用
Proxy.newProxyInstance
创建代理对象。import java.lang.reflect.Proxy; public class JDKProxyDemo { public static void main(String[] args) { HelloService target = new HelloServiceImpl(); HelloService proxy = (HelloService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new MyInvocationHandler(target) ); proxy.sayHello(); } }
2. Cglib 动态代理
Cglib 代理通过继承被代理的类来创建代理对象,因此不需要被代理的类实现接口。Cglib 主要用于类级别的代理。
详细实现步骤:
-
添加 Cglib 依赖:首先,需要在项目中引入 Cglib 依赖(如果使用 Maven)。
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
-
定义普通类:创建一个需要被代理的普通类。
public class HelloService { public void sayHello() { System.out.println("Hello, world!"); } }
-
实现 MethodInterceptor:实现
MethodInterceptor
接口以定义拦截逻辑。import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class MyMethodInterceptor implements MethodInterceptor { private Object target; public MyMethodInterceptor(Object target) { this.target = target; } @Override public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before method: " + method.getName()); Object result = proxy.invoke(target, args); System.out.println("After method: " + method.getName()); return result; } }
-
创建代理对象:使用
Enhancer
来创建代理对象。import net.sf.cglib.proxy.Enhancer; public class CglibProxyDemo { public static void main(String[] args) { HelloService target = new HelloService(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(new MyMethodInterceptor(target)); HelloService proxy = (HelloService) enhancer.create(); proxy.sayHello(); } }
3. Spring AOP 的 Cglib 代理
Spring AOP 可以通过 Cglib 代理来实现对类的增强。Spring AOP 在底层使用了 Cglib 来生成代理类,尤其在被代理的类没有实现接口时。
详细实现步骤:
-
添加 Spring AOP 依赖:在项目中引入 Spring AOP 相关的依赖(如果使用 Maven)。
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.3.24</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.24</version> </dependency>
-
定义服务类:创建一个使用 Spring 注解的服务类。
import org.springframework.stereotype.Service; @Service public class HelloService { public void sayHello() { System.out.println("Hello, world!"); } }
-
创建切面类:使用
@Aspect
注解定义切面,并实现切面逻辑。import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { @Around("execution(* HelloService.sayHello(..))") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Before method: " + joinPoint.getSignature().getName()); Object result = joinPoint.proceed(); System.out.println("After method: " + joinPoint.getSignature().getName()); return result; } }
-
配置 Spring AOP:配置 Spring 来启用 AOP 功能。
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy @ComponentScan(basePackages = "your.package") public class AppConfig { }
-
主程序:使用 Spring 上下文来获取服务类的代理对象。
import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class SpringAopDemo { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); HelloService helloService = context.getBean(HelloService.class); helloService.sayHello(); } }
总结
- JDK 动态代理:适用于代理实现了接口的类,使用
java.lang.reflect.Proxy
生成。 - Cglib 代理:适用于代理没有实现接口的类,通过继承生成代理类。
- Spring AOP Cglib 代理:Spring 使用 Cglib 实现对类的增强,支持注解方式的切面编程。
hutool工具包实现方式
引入hutool工具包
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.6</version>
</dependency>
ProxyFactory生成代理对象
- CglibProxyFactory 基于Cglib的切面代理工厂
- JdkProxyFactory JDK实现的切面代理
- SpringCglibProxyFactory 基于Spring-cglib的切面代理工厂
- createProxy
createProxy默认使用Cglib 动态代理
- 如何使用
public void test(){
Cat proxy = ProxyFactory.createProxy(new Cat(), SimpleAspect.class);
proxy.eat();
}
new Cat()为目标对象,SimpleAspect.class为切面对象,hutool提供了两个切面对象类
- SimpleAspect类,是基本类,所有自定义开发的切面对象都需要集成该类
- TimeIntervalAspect类,为通过日志打印方法的执行时间的切面
public void TimeIntervalAspectTest(){
Cat proxy = ProxyFactory.createProxy(new Cat(), TimeIntervalAspect.class);
proxy.eat();
}
2. proxy
如果不想使用默认的的Cglib 动态代理,可以使用该方法自定义创建
@Test
public void ProxyTest(){
ProxyFactory proxyFactory = new ProxyFactory() {
@Override
public <T> T proxy(T target, Aspect aspect) {
/**
* 1、CglibProxyFactory 基于Cglib的切面代理工厂
* 2、JdkProxyFactory JDK实现的切面代理
* 3、SpringCglibProxyFactory 基于Spring-cglib的切面代理工厂
*/
return JdkProxyFactory.createProxy(target, aspect);
}
};
Cat proxy = ProxyFactory.createProxy(new Cat(), TimeIntervalAspect.class);
proxy.eat();
}
如何创建自己的切面对象类
- 继承SimpleAspect简单切面类
简单切面类,不做任何操作 可以继承此类实现自己需要的方法即可
public class MyAopAspect extends SimpleAspect {
@Override
public boolean before(Object target, Method method, Object[] args) {
System.out.println("before");
return true;
}
@Override
public boolean after(Object target, Method method, Object[] args, Object returnVal) {
System.out.println("after");
return true;
}
@Override
public boolean afterException(Object target, Method method, Object[] args, Throwable e) {
System.out.println("afterException");
return true;
}
}
@Test
public void testMyAopAspect(){
Cat proxy = ProxyFactory.createProxy(new Cat(), MyAopAspect.class);
proxy.eat();
}