1. 功能简介
动态代理是一种在运行时创建代理对象并拦截方法调用的技术。通过动态代理,我们可以在方法执行前后插入自定义逻辑,这种方式常用于日志记录、事务管理、安全检查等场景。在Java中,java.lang.reflect.Proxy
类提供了动态代理的功能。
AOP(面向切面编程)允许我们通过配置将横切关注点(如日志、性能监控等)与核心业务逻辑解耦开来,使得代码更加模块化。结合动态代理,我们可以实现简单的AOP框架,在方法执行前后增加自定义逻辑。
2. 代码实现
1. LogAspect
类:定义日志切面(前置和后置通知)
首先,定义一个切面类 LogAspect
,用于记录方法调用的日志。
package com.example.aop;
import java.lang.reflect.Method;
public class LogAspect {
// 前置通知:方法执行前
public void before(Method method, Object[] args) {
System.out.println("Before method: " + method.getName() + ", Arguments: " + (args != null ? args.length : 0));
}
// 后置通知:方法执行后
public void after(Method method, Object[] args, Object result) {
System.out.println("After method: " + method.getName() + ", Result: " + result);
}
}
2. DynamicProxy
类:动态代理实现
DynamicProxy
类通过 Proxy.newProxyInstance
方法生成代理对象,拦截调用并执行切面逻辑。
package com.example.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy {
// 创建代理对象
public static Object createProxy(Object target, LogAspect logAspect) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置通知
logAspect.before(method, args);
// 调用目标对象的方法
Object result = method.invoke(target, args);
// 后置通知
logAspect.after(method, args, result);
return result;
}
});
}
}
3. UserService
接口:服务接口
定义一个简单的接口 UserService
,该接口包含一个方法用于获取用户信息。
package com.example.aop;
public interface UserService {
String getUserInfo(int userId);
}
4. UserServiceImpl
类:实现接口
UserServiceImpl
类实现了 UserService
接口,模拟获取用户信息的业务逻辑。
package com.example.aop;
public class UserServiceImpl implements UserService {
@Override
public String getUserInfo(int userId) {
// 模拟获取用户信息
return "User Info for userId: " + userId;
}
}
5. App
类:主程序
主程序类通过动态代理和切面实现,演示了如何在方法执行前后添加日志记录。
package com.example.aop;
public class App {
public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 创建切面对象
LogAspect logAspect = new LogAspect();
// 使用动态代理生成代理对象
UserService proxy = (UserService) DynamicProxy.createProxy(userService, logAspect);
// 调用代理对象的方法
System.out.println(proxy.getUserInfo(123));
}
}
3. 使用说明
1. LogAspect 类:
- 功能:用于定义切面(前置通知和后置通知)。前置通知在方法执行之前调用,后置通知在方法执行之后调用。
- 方法:
before(Method method, Object[] args)
:方法执行前的处理,用于记录日志或其他操作。after(Method method, Object[] args, Object result)
:方法执行后的处理,用于记录日志或处理返回值。
2. DynamicProxy 类:
- 功能:该类使用
Proxy.newProxyInstance
动态生成代理对象,拦截方法调用并执行切面逻辑(前置通知和后置通知)。 - 方法:
createProxy(Object target, LogAspect logAspect)
:接收目标对象和切面对象,生成代理对象。
3. UserService 接口:
- 功能:定义业务逻辑接口,示例中提供了
getUserInfo
方法,模拟获取用户信息。
4. UserServiceImpl 类:
- 功能:实现
UserService
接口,模拟实际的业务操作。
5. App 类:
- 功能:主程序,演示如何通过动态代理和AOP结合,自动记录方法调用日志。
6. 执行流程:
- 创建
UserService
的目标对象userService
,以及切面对象logAspect
。 - 使用
DynamicProxy
创建代理对象proxy
,通过代理对象来调用getUserInfo
方法。 - 在调用
proxy.getUserInfo(123)
时,方法的前置通知会先执行,记录调用日志;方法执行完毕后,后置通知会记录返回值。
4. 示例输出
Before method: getUserInfo, Arguments: 1
After method: getUserInfo, Result: User Info for userId: 123
User Info for userId: 123
5. 总结
本例实现了一个简化的 AOP 框架,通过动态代理为业务方法添加日志记录功能。该实现具有以下特点:
- 动态代理:通过
Proxy.newProxyInstance
动态创建代理对象,不需要手动编写代理类。 - 切面功能:通过切面
LogAspect
实现了方法执行前后的日志记录,能够灵活地为其他方法添加横切功能。 - 模块化:业务逻辑和切面逻辑(如日志记录)解耦,提高了代码的可维护性和扩展性。
这种方式广泛应用于日志、事务、权限等功能的实现,特别适合大型企业应用的开发。