(设计模式-代理模式)
JDK静态代理、JDK动态代理和CGLIB动态代理
Spring中的AOP是离不开代理模式的
Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理。
不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。
动态代理能够在被代理的类的方法执行前和执行后进行处理,主要用来解决一些系统层面上的问题
比如日志,事务,权限等
静态代理实现方法
实现原理:
就是创建一个代理类,代理类和被代理类实现同一个接口,将被代理类以构造参数的方法传入代理类
调用代理类的方法时,代理类先调用自己的方法再调用被代理类的方法,然后再调用自己的方法
public class Proxy implements IUserService{
private IUserService userService; //将需要被代理的类创建出来
public Proxy(IUserService userService)
{
this.userService=userService; //赋值被代理的类
}
@Override
public void insertRandomUser() {
System.err.println("执行前"); //执行前处理
userService.insertRandomUser();
System.err.println("执行后"); //执行后处理
}
@Override
public void printlnRandomUser() {
System.err.println("执行前"); //执行前处理
userService.printlnRandomUser();
System.err.println("执行后"); //执行后处理
}
public static void main(String[] args) {
Proxy proxy=new Proxy(new UserService()); //创建被代理的类和代理类
proxy.insertRandomUser(); //代理类执行
proxy.printlnRandomUser(); //代理类执行
}
使用jdk动态代理时我们需要先创建一个接口、一个继承该接口的类和一个代理类
(如:接口 IUserService、继承类UserService、代理类ProxyPattern)
为了更容易理解代理模式,我在里面还添加了一个User类
//User类
public class User {
private String name;
private Integer age;
private Boolean sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getSex() {
return sex;
}
public void setSex(Boolean sex) {
this.sex = sex;
}
@Override
public String toString() {
return "name="+name+",age="+age+",sex="+sex;
}
}
这是接口 IUserService
接口中定义了两个方法
//接口
public interface IUserService {
//添加user对象
void insertRandomUser();
//删除user对象
void printlnRandomUser();
}
这是继承类了接口的 UserService 类
类中对两个接口进行了实现并且添加了一个静态变量userList
//继承类
public class UserService implements IUserService {
//用来保存user对象
private static List<User> userList=new ArrayList<User>();
public void insertRandomUser() {
User user=new User();
int size=userList.size();
user.setAge(new Random().nextInt(100));
user.setName(String.valueOf(new Random().nextInt(100)));
user.setSex(new Random().nextBoolean());
userList.add(user);
System.err.println("添加成功,剩余对象"+(size-1));
System.err.println(user.toString());
}
public void printlnRandomUser() {
int size=userList.size();
if(size<=0)
{
System.err.println("没有对象了");
return;
}
System.err.println("取出成功,剩余对象"+(size-1));
int number=new Random().nextInt(size);
User user=userList.get(number);
userList.remove(number);
System.err.println(user.toString());
}
}
最后是代理类
public class ProxyPattern<T> implements InvocationHandler {
private static int proxyNum=0;
private T obj;
public ProxyPattern(T obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理执行" + method.getName() + "方法");
Object result = method.invoke(obj, args);
System.out.println("方法" + method.getName() + "执行完毕");
proxyNum++;
System.out.println("当前类执行了"+proxyNum+"次");
return result;
}
public static void main(String[] args) {
IUserService userServce=new UserService();
InvocationHandler handler = new ProxyPattern<IUserService>(userServce);
IUserService moveable = (IUserService) Proxy.newProxyInstance(IUserService.class.getClassLoader(), new Class<?>[] {IUserService.class} , handler);
while(true)
{
try {
Thread.sleep(1000);
if(new Random().nextBoolean())
{
moveable.insertRandomUser();
}
else
{
moveable.printlnRandomUser();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
CGLIB jar包下载地址
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
cglib 动态代理实现
cglib 的实现和jdk的实现是极其相似的,jdk动态代理是基于接口进行实现,cglib则是基于类实现
在spring的AOP中,需要被代理的类是接口则采用jdk的实现,需要被代理的类不是接口则采用cglib的实现
public class CGLIBProxyPattern implements MethodInterceptor{
public static void main(String[] args) {
UserService userService = new UserService(); //创建service层对象
CGLIBProxyPattern cglib = new CGLIBProxyPattern(); //创建代理对象
Enhancer enhancer = new Enhancer(); //创建代理类创建器
enhancer.setSuperclass(userService.getClass()); //设置创建类型为UserService。class
enhancer.setCallback(cglib); //设置代理对象(代理对象需要继承MethodInterceptor接口)
IUserService hose = (IUserService) enhancer.create(); //创建代理后的对象
hose.insertRandomUser(); //调用方法
hose.printlnRandomUser(); //调用方法
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("执行前"); //调用方法前执行
Object o = methodProxy.invokeSuper(obj, args); //调用原方法
System.out.println("执行后"); //调用方法后执行
return o;
}