1、何为代理模式
如何实现在不修改源码的基础上实现代码功能的增强呢?spring为我们提供了代理模式。所谓的代理模式通俗来说就是一个中介,它给某一个对象提供一个代理对象,并由代理对象控制原对象的引用,从而实现在不修改源码的基础上实现代码功能的增强。
2、分类
按照代理创建的时期进行分类,可以分为两类:静态代理、动态代理。
静态代理的代理类=原始类+增强(额外功能)+和原始类实现同一个接口,即基于接口的代理。
动态代理又分为jdk动态代理,其也是基于接口的代理;cglib的动态代理。
三、实验的代码:
新建实体类User.class
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String username;
private String password;
}
其中使用lombok实现实体类的所有方法。
新建接口UserService
public interface UserService {
boolean addUser(User user);
Integer delete(Integer id);
}
新建实现类UserServiceImpl
public class UserServiceImpl implements UserService{
@Override
public boolean addUser(User user) {
System.out.println("service核心业务:添加用户对象"+user);
return false;
}
@Override
public Integer delete(Integer id) {
System.out.println("service核心业务:一个用户对象被删除,id = "+id);
return null;
}
}
编写测试代码test01
@org.junit.Test
public void test01(){
UserServiceImpl userService = new UserServiceImpl();
User user = User.builder().username("tom").password("root").build();
userService.addUser(user);
}
测试结果为:
现在添加日志打印功能
public class UserServiceImplStaticProxy implements UserService {
private UserServiceImpl userService = new UserServiceImpl();
@Override
public boolean addUser(User user) {
// 添加日志的打印功能
System.out.println("-----------log-----------");
// 调用原始类中添加用户的方法 核心业务
userService.addUser(user);
return false;
}
@Override
public Integer delete(Integer id) {
return null;
}
}
重新编写两个测试代码test01
@org.junit.Test
public void test02(){
UserServiceImplStaticProxy userService = new UserServiceImplStaticProxy();
User user = User.builder().username("jason").password("123").build();
userService.addUser(user);
}
可以看到日志功能已经添加成功
接下来看基于jdk的动态代理
@org.junit.Test
public void test03(){//基于jdk的动态代理
// 原始类
UserServiceImpl userService = new UserServiceImpl();
/**
* ClassLoader:类加载器 java程序执行 编写源码 .java->编译 .class ---类加载器--- -> jvm 执行
* jvm虚拟机会针对每一个class文件 分配一个ClassLoader
* 作用:
* 1、加载class文件到jvm虚拟机
* 2、生成该文件对应的Class对象(类对象),从而创建实体类对象
*
* 代理类不会被分配类加载器,但是可以借用其他类的加载器,实现程序的运行
*
* interface:原始类实现的接口
* invocationHandler:额外的功能
*/
// 业务增强的逻辑代码
InvocationHandler invocationHandler = new InvocationHandler() {
/**
* Object proxy:代表生成的代理对象
* Method method:原始类中被调用的方法
* Object[] args:调用方法的参数列表
* 返回值 Object:原始类方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//添加日志的打印功能
System.out.println("------jdk log-----");
System.out.println("原始类中被调用方法名子:"+method.getName());
System.out.println("调用方法的参数列表是:"+ Arrays.toString(args));
//调用原始类的方法
Object invoke = method.invoke(userService, args);
return invoke;
}
};
// 创建动态代理对象 userService $proxy
UserService userService1 = (UserService)Proxy.newProxyInstance(Test.class.getClassLoader(), userService.getClass().getInterfaces(), invocationHandler);
User user = User.builder().password("123").username("jason").build();
// invoke
userService.addUser(user);
}
最后再看基于cglib的动态代理
@org.junit.Test
public void test04(){//基于cglib的动态代理,基于父子关系创建代理对象
UserServiceImpl2 userServiceImpl2 = new UserServiceImpl2();
Enhancer enhancer = new Enhancer();
// 设置相关参数
enhancer.setClassLoader(this.getClass().getClassLoader());
enhancer.setSuperclass(userServiceImpl2.getClass());
// Callback增强的业务,类似jdk中的invoke方法
MethodInterceptor methodInterceptor = new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("-----------cglib log-------------");
Object invoke = method.invoke(userServiceImpl2,objects);
return invoke;
}
};
enhancer.setCallback(methodInterceptor);
//通过enhancer创建代理对象
UserServiceImpl2 userServiceImpl21 = (UserServiceImpl2)enhancer.create();
User jason = User.builder().username("jason").password("123").build();
userServiceImpl21.addUser(jason);
}