面试的时候,java开发必问的知识点是spring,spring中核心的是IOC和AOP。问到AOP的实现原理的时候,咱们都知道是代理模式,却对代理模式只知其一;不知其二,今天就来记记笔记。
下面借鉴一张代理模式的导图:java
首先假设一种业务场景,须要实现对用户进行CRUD的操做,因此咱们建立了一个UserService接口和UserServiceImpl的实现类。代码以下:面试
public interface UserService {
void addUser();
void updateUser();
}
public class UserServiceImpl implements UserService{
@Override
public void addUser() {
System.out.println("添加一个用户");
}
@Override
public void updateUser() {
System.out.println("更新一个用户");
}
}
复制代码
如今咱们须要在每次对用户信息进行增长、删除和更新操做的时候记录一下日志,用静态代理的方式,咱们须要建立一个静态代理类,将被代理对象(目标对象)传入,而后建立须要加强的方法,如addUser和updateUser,实现记录日志的功能spring
public class UserStaticProxy {
private UserService userService;
public UserStaticProxy(UserService userService) {
this.userService=userService;
}
public void addUser() {
userService.addUser();
System.out.println("打印一条日志");
}
}
复制代码
测试bash
public class StaticProxyTest {
public static void main(String [] args) {
UserService userService = new UserServiceImpl();
UserStaticProxy staticProxy = new UserStaticProxy(userService);
staticProxy.addUser();
}
}
复制代码
运行结果:ide
一、接口增长方法,代理类须要同步维护。
二、接口越多,须要建立的代理类就越多。好比之后咱们有TeacherService,StudentService,就须要建立TeacherStaticProxy,StudentStaticProxy,这样就增长了代码量。函数
其实动态代理和静态代理的本质是同样的,最终程序运行时都须要生成一个代理对象实例。只不过静态代理是采用硬编码的方式在程序运行以前就建立好代理类,而动态代理是运行时动态生成的方式。
JDk帮咱们实现了动态代理,使用的是newProxyInstance方法
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
该方法中接收三个参数:
ClassLoader loader,:指定当前目标对象使用类加载器
Class<?>[] interfaces,:代理类须要实现的接口列表
InvocationHandler h:调用处理程序,将目标对象的方法分派到该调用处理程序
代码示例:学习
public class DynamicProxy implements InvocationHandler{
private Object target;//目标对象
public Object bind(Object target) {
this.target=target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Exception{
//执行目标对象的方法
Object result = method.invoke(target,args);
//实现扩展功能
System.out.println("打印一下日志");
return result;
}
}
复制代码
bind方法简单封装jdk的newProxyInstance(),并返回目标接口对象。invoke方法负责加强目标对象的方法,实现扩展功能。
测试类:测试
public class DynamicProxyTest {
public static void main(String [] args) {
DynamicProxy dynamicProxy = new DynamicProxy();
UserService userService = (UserService) dynamicProxy.bind(new UserServiceImpl());
userService.addUser();
userService.updateUser();
}
}
复制代码
运行结果: ui
上面两种代理方式,目标对象UserServiceimpl都实现了一个接口,若是只是一个普通的类,没有实现任何接口,该如何进行代理呢?这就引出了CGLib动态代理。CGLib动态代理也叫子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。
要用cglib代理,须要导入相应的包,好在spring已经集成了它,引入spring便可。
代理类:this
public class CGLibProxy implements MethodInterceptor {
private Object target;
public Object bind(Object target) {
this.target=target;
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(this.target.getClass());
//设置回调函数
enhancer.setCallback(this);
//建立并返回子类对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable{
Object object = methodProxy.invokeSuper(o,objects);
System.out.println("打印一下日志");
return object;
}
}
复制代码
测试类:
public class CGLibProxyTest {
public static void main(String [] args) {
CGLibProxy cgLibProxy = new CGLibProxy();
UserService userService = (UserService) cgLibProxy.bind(new UserServiceImpl());
userService.addUser();
userService.updateUser();
}
}
复制代码
运行结果:
今天的笔记就记到这里,感谢前来阅读的大家,咱们一块儿学习,一块儿进步。