代理模式就是Spring AOP的底层。
代理模式的分类:
- 静态代理
-
静态代理
例子:租房的人,中介,房东三方。而中介就是代理人,通过第三方代理人来租房。
分析过程: 抽象角色:就是要共同完成的的事,一般使用接口或抽象类解决。
- 真实角色:被代理的角色。
- 代理角色:代理真实的角色,代理后,用来添加一些附属的操作。
- 客户:访问代理的对象的人、
好处:
可以让真实角色更加纯粹,不用管理公共的业务。公共交给大力角色,实现业务分工。公共业务扩展的时候,也方便管理。
缺点:
一个真实角色产生一个代理,代码量多且开发效率低。
就像DAO层实现业务,Service层代理添加业务,Controller层调用。 dao层业务代码量多,无法随便修改,一旦出现问题就全部崩盘,使用代理添加业务逻辑能更好的开发。
//dao层
/**
* @author:刘倩云
* @createTime:2021-03-17
*/
public class UserDAOImpl implements UserDAO {
public void save() {
System.out.println("添加用户");
}
public void delete() {
System.out.println("删除用户");
}
}
//service层
/**
* @author:刘倩云
* @createTime:2021-03-17
*/
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
public void save() {
log("save");
userDAO.save();
}
public void delete() {
log("delete");
userDAO.delete();
}
public void log(String msg){
System.out.println("使用了"+msg+"方法");
}
}
动态代理
动态代理和静态代理的角色一样
动态代理的代理类是自动生成的,不是我们直接写好的。
动态代理分为两类:
- 基于接口的动态代理 :JDK动态代理
- 基于类的动态代理:cglib
需要了解两个类:Proxy:代理,生成代理类
InvocationHandler:调用处理程序
写一个类似于工具类的公共类,把公共部分提取出来,直接调用传入需要的参数。
JDK动态代理
//dao层
/**
* @author:刘倩云
* @createTime:2021-03-17
*/
public interface UserDAO {
void save();
void delete();
}
/**
* @author:刘倩云
* @createTime:2021-03-17
*/
public class UserDAOImpl implements UserDAO {
public void save() {
System.out.println("添加用户");
}
public void delete() {
System.out.println("删除用户");
}
}
准备一个代理类
步骤:
- 成员变量为代理目标
- 有参构造传入代理目标
- 获取代理对象的方法:
方法中使用 Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {})
/**
* @author:刘倩云
* @createTime:2021-03-18
*/
public class JDKProxyFactory {
private Object target; //被代理目标对象
public JDKProxyFactory(Object target){
this.target = target;
}
//返回代理对象
public Object getObject(){
//传入对应的参数
Class clazz = target.getClass();
//使用匿名内部类直接实现InvocationHandler
Object obj = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
/**
* @param proxy 代理的实例
* @param method 被增强的方法
* @param args 被增强方法的参数列表
* @return 被增强方法的返回值
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("被增强的对象:"+target);
System.out.println("方法名:"+method.getName());
System.out.println("----------------------");
//通过反射调用目标方法
Object returnVal = method.invoke(target, args);
System.out.println("-----------------------");
System.out.println("目标增强后");
System.out.println("方法返回值:"+returnVal);
return returnVal;
}
});
return obj;
}
}
测试
@Test
public void testJDKProxy(){
UserDAO userDAO = new UserDAOImpl();
//创建工厂,传入目标对象
JDKProxyFactory factory = new JDKProxyFactory(userDAO);
UserDAO object = (UserDAO) factory.getObject();
object.save();
}
总结
JDK代理不会代理接口中没有的方法。
tips:JDK的动态代理是按照接口代理的。接口中没有的方法,无法代理。
其实JDK的动态代理就是JDK自己帮我们实现了那个静态代理中的代理类。
cglib代理
添加cglib包
<!-- 添加cglib包-->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
工厂
/**
* @author:刘倩云
* @createTime:2021-03-18
*/
public class CglibProxyFactory {
//创建目标成员
private Object target;
public CglibProxyFactory(Object target){
this.target = target;
}
public Object getObject(){
//创建一个增强对象
Enhancer enhancer = new Enhancer();
//设置父类类型
enhancer.setSuperclass(target.getClass());
//设置处理器
enhancer.setCallback(new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("被增强的对象:"+target);
System.out.println("方法名:"+method.getName());
System.out.println("----------------------");
//通过反射调用目标方法
Object returnVal = method.invoke(target, args);
System.out.println("-----------------------");
System.out.println("目标增强后");
System.out.println("方法返回值:"+returnVal);
return returnVal;
}
});
//创建对象并且返回
return enhancer.create();
}
}
测试
@Test
public void testCglibProxy(){
UserDAOImpl userDAO = new UserDAOImpl();
//创建工厂,传入目标对象
CglibProxyFactory factory = new CglibProxyFactory(userDAO);
UserDAOImpl object = (UserDAOImpl) factory.getObject();
object.update();
}
总结**
CGLib的动态代理是可以代理接口中没有的方法。
主要的原因是,CGLib增强一个方法是使用继承实现的。