一、什么是代理模式
代理模式:为其他对象提供一种代理以控制对这个对象的访问。
好处:可以控制被代理类的访问和行为。在不修改被代理类的情况下对被代理类的访问做出修改。
二、代理分类
代理分为:
静态代理:编译期已经确定了被代理的对象和代理类。
- 代理类和被代理类实现同样的接口(保证行为一致)
- 代理类持有一个被代理类对象(保证代理类能够调用到被代理类)
动态代理:在运行期间才确定被代理的对象,并动态生成一个代理类。
三、静态代理
就用一个简单的例子来介绍静态代理吧,比如清朝皇帝溥仪被太后慈禧操控,垂帘听政,这里被代理人就是溥仪,而代理人就是慈禧
① 先写一个King接口
package proxy.staticproxy;
public interface King {
void shangchao(); // 上朝
void pingshen(); // 平身
}
② 慈禧实现King接口
package proxy.staticproxy;
import java.util.Random;
public class CiXi implements King {
private FuYi fuYi;
public CiXi(FuYi fuYi) {
this.fuYi = fuYi;
}
@Override
public void shangchao() {
Random rd = new Random();
int i = rd.nextInt(10);
System.out.println(i);
if(i%2==1){
fuYi.shangchao();
}else{
System.out.println("太后上朝");
}
}
@Override
public void pingshen() {
fuYi.pingshen();
}
}
③ 溥仪实现King接口
package proxy.staticproxy;
public class FuYi implements King {
@Override
public void shangchao() {
System.out.println("皇帝上朝!");
}
@Override
public void pingshen() {
System.out.println("众卿平身!");
}
}
④ 编写测试类
package proxy.staticproxy;
public class Test {
public static void main(String[] args) {
// 静态代理
FuYi fuYi = new FuYi();
// 慈禧代理
King king = new CiXi(fuYi);
king.shangchao();
king.pingshen();
}
}
⑤ 运行结果
四、动态代理
Java中动态代理有两种:
Jdk动态代理:通过反射来创建代理类。被代理类和代理类实现同样的接口。(必须有共同的接口)
- 实现共同的接口,需要定义一个共同的接口。
- 需要定义代理类的回调类,该类需要实现InvokecationHandler接口,在invoke方法中编写代理类的逻辑
- 需要通过反射的API,生成代理类。
Cglib动态代理:通过编辑字节码文件来生成一个代理类。生成的代理类继承自被代理类。
- 导入cglib依赖
- 实现MethodInterceptor接口
代理类和被代理类如何保证行为一致?
- 实现同样的接口
- 继承关系
Jdk动态代理
① 创建被代理接口
package proxy;
import entity.Admin;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Select;
public interface AdminMapper {
@Delete("delete from t_admin where id=#{id}")
int delete(Integer id);
@Select("select id,name,phone from t_admin where id=#{id}")
Admin selectById(Integer id);
}
② 创建生成代理类的类
public class MapperProxy implements InvocationHandler {
public Object getMapper(Class mapperClass){
return Proxy.newProxyInstance(
mapperClass.getClassLoader(), // 被代理类的类加载器
new Class[]{mapperClass}, // 被代理类实现的接口
this // InvocationHandler对象
);
}
/**
* 回调方法,在调用代理类的方法时会触发该方法
* @param proxy 代理对象
* @param method 调用的方法
* @param args 方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 这里写的是一些业务逻辑
// Delete annotation = method.getAnnotation(Delete.class);
// if(annotation!=null){
// String[] s = annotation.value();
// String sql = s[0];
// sql = sql.replaceAll("#\\{\\w+\\}", "?");
// System.out.println(sql);
// Connection connection = null;
// PreparedStatement ps = null;
// int res = 0;
// try {
// Class.forName("oracle.jdbc.driver.OracleDriver");
// connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE", "blog", "123456");
// ps = connection.prepareStatement(sql);
// for (int i = 0; i < args.length; i++) {
// ps.setObject(i+1, args[i]);
// }
// res = ps.executeUpdate();
// // 事务提交
// connection.commit();
// } catch (ClassNotFoundException e) {
// e.printStackTrace();
// } catch (SQLException e) {
// e.printStackTrace();
// connection.rollback();
// } finally {
// ps.close();
// connection.close();
// }
// return res;
// }
// return null;
}
}
③ 编写测试类
public class Test {
public static void main(String[] args) throws IOException {
// 通过传入Class对象动态的生成代理类
AdminMapper mapper = (AdminMapper) new MapperProxy().getMapper(AdminMapper.class);
// 调用delete方法后会自动调用invoke方法并执行其中的业务逻辑
mapper.delete(5);
}
}
Cglib动态代理
① 在maven项目中导入cglib依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.12</version>
</dependency>
② 创建生成代理类的类
package proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
private Object obj; // 存储被代理对象
// 生成代理对象
public Object getProxy(Object obj){
this.obj = obj;
return Enhancer.create(
obj.getClass(), // 被代理对象
this // MethodInterceptor接口类实现对象
);
}
/**
* 代理对象调用方法的时候触发
* @param o 代理对象
* @param method 执行的方法
* @param objects 参数
* @param methodProxy 代理方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
String name = method.getName();
if(name.startsWith("set")){
System.out.println("set方法不允许操作!");
return null;
}
// 执行方法,通过代理方法调用被代理的方法
Object o1 = method.invoke(obj, objects);
return o1;
}
}
③ 编写测试类
package proxy.cglib;
import entity.Admin;
public class Test {
public static void main(String[] args) {
Admin admin = new Admin(1, "admin", "111", "tom", "222", "333", "1", "男");
Admin proxy = (Admin) new CglibProxy().getProxy(admin);
proxy.setName("lala");
System.out.println(proxy.getName());
}
}
④ 运行结果