Spring与代理模式
- 为了阐述清楚spring中的一个非常重要的模块AOP,必须要了解代理模式
- 代理模式就是为其他对象提供一种代理以控制对这个对象的访问
- 白话解释为:
- 比如A对象要做一件事,在没有代理之前,需要自己亲自动手
- 在对A代理后,这件事就由A的代理来做
- 代理其实是在原始的实例前后增加了一层处理,这也就是AOP概念的初级轮廓
1.静态代理
- 在程序的运行前就已经存在代理类的字节码文件,代理类和原始类的关系在运行前就已经确定!
代码:
UserDao.java
public interface UserDao {
void add();
}
UserDaoImpl.java
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("模拟,添加用户!");
}
}
UserDaoProxy.java
public class UserDaoProxy implements UserDao {
// 授权
private UserDao ud = new UserDaoImpl();
@Override
public void add() {
System.out.println("代理操作:开启事务,为你遮风挡雨");
ud.add();
System.out.println("代理操作:提交事务,为你保驾护航");
}
}
Test.java
public class Test {
public static void main(String[] args) {
UserDao ud = new UserDaoProxy();
ud.add();
}
}
总结:如果增加一个方法,除了实现类需要实现这个方法外,所有的代理类也要实现这个方法。增加了代码的维护成本。
静态代理就是有这样的问题,想解决这个问题,使用“动态代理”
2.动态代理-JDK
- 动态代理类的源码是在程序运行期间,通过JVM反射等机制动态生成,代理类和委托类的关系是运行时才确定的
UserDao.java
public interface UserDao {
void add();
void findAll();
}
UserDaoImpl.java
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("模拟,保存用户!");
}
@Override
public void findAll() {
System.out.println("查询所有用户");
}
}
UserDaoProxy.java
public class UserDaoProxy implements InvocationHandler {
/// 目标,委托类
private Object target;
// 授权
public Object getProxyInstance(Object object) {
this.target = object;
/*
newProxyInstance(1,2,3);
1:目标对象使用的类加载器
2:目标对象实现的所有接口
3:代理对象
*/
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Object result = null;
//查询方法不需要加事务,其他的增删改都需要事务管理
// findAll,findOneById
if (methodName.indexOf("find") >= 0) { // 匹配查询方法
result = method.invoke(target, args); //执行目标方法
} else { //增删改
System.out.println("开始事务");
result = method.invoke(target, args);//执行目标方法
System.out.println("结束事务");
}
return result;
}
}
Test.java
public class Test {
public static void main(String[] args) {
// 目标对象
UserDao ud = new UserDaoImpl();
// 代理对象
UserDaoProxy proxy = new UserDaoProxy();
// 代理实例
UserDao proxyInstance = (UserDao) proxy.getProxyInstance(ud);
proxyInstance.add();
System.out.println("----------------------------");
proxyInstance.findAll();
}
}
总结:使用JDK生成的动态代理的前提是目标对象必须有实现的接口,这里又引入一个新的问题,如果某个类没有实现接口,就不能用这种代理方式。Cglib代理就是解决这个问题的。
3.动态代理-Cglib
- 如果是普通的项目,需要引入cglib-xxx.jar和ams-xx.jar两个文件
- 如果是spring项目,spring对cglib是支持的。
- 此代理方式的原理:拦截器(80%和过滤器概念一样)
UserDao.java
public class UserDao {
public void add(){
System.out.println("模拟,保存用户!");
}
}
UserDaoProxy.java
package proxy3;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @BelongsProject: spring2
* @Author: GuoAn.Sun
* @CreateTime: 2020-06-29 12:12
* @Description: ${Description}
*/
public class UserDaoProxy implements MethodInterceptor {
//目标对象
private Object target;
//获得代理对象
public Object getInstance( 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 {
System.out.println("事务开始");
Object result = methodProxy.invoke(target, objects);
System.out.println("事务结束");
return result;
}
}
Test.java
public class Test {
public static void main(String[] args) {
//目标
UserDao ud = new UserDao();
//代理
UserDaoProxy proxy = new UserDaoProxy();
UserDao dao = (UserDao) proxy.getInstance(ud);
dao.add();
}
}