什么是代理模式?
代理(Proxy)是一种设计模式,为其他对象提供一种代理以控制对这个对象的访问。
代理模式的组成
- 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
- 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
- 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
代理模式的优点
(1).职责清晰
真实的角色就是实现实际的[业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
(2).代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。
(3).高扩展性
代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象。
一、静态代理
步骤1:创建接口 Animal.java
/**
* 静态代理步骤1
* -创建接口
* */
public interface Animal {
void run();
void eat();
}
步骤2:创建实现类并实现步骤1的接口 AnimalImpl.java
/**
* 静态代理步骤 2
* -创建实现类并实现步骤1的接口
* */
public class AnimalImpl implements Animal{
@Override
public void run() {
System.out.println("猎豹跑的都很快");
}
@Override
public void eat() {
System.out.println("动物为了生存,一般都喜欢进食");
}
}
步骤3:创建代理类并实现步骤1的接口 StaticProxy.java
/**
* 静态代理步骤 3
* -创建代理类并实现步骤1的接口
* */
public class StaticProxy implements Animal{
private Animal animal;// 目标对象
// 构造函数
StaticProxy(){}
StaticProxy(Animal _animal){
this.animal = _animal;
}
@Override
public void run() {
System.out.println("事物开始前");
animal.run();
System.out.println("事物开始后");
}
@Override
public void eat() {
System.out.println("事物开始前");
animal.eat();
System.out.println("事物开始后");
}
}
步骤4:实现代理方法:
/**
* 静态代理步骤4
* -实现静态代理方法
* */
public class TestMain {
/**
* 总结:
*
* 静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现接口或继承相同 的父类
* 缺点:
*
* 因为代理对象需要和被代理对象实现相同的接口或父类,所以会有太多的代理类
* 一旦接口中增加了方法后,被代理对象和代理对象都需要维护(非常麻烦,不方便)
* */
public static void main(String[] args) {
//1.创建目标对象(通过目标实现类创建目标对象)
Animal animal = new AnimalImpl();
//2.创建代理对象(将目标对象传递进代理对象,建立代理关系)
StaticProxy staticProxy = new StaticProxy(animal);
//3.执行方法
staticProxy.run();
staticProxy.eat();
}
运行结果:
二、JDK动态代理
步骤1:创建接口 Persion.java
/**
* JDK动态代理步骤1
* -创建接口
* */
public interface Persion {
void say();
}
步骤2:创建实现类并实现步骤1的接口PersionImpl.java
/**
* JDK动态代理步骤2
* -创建实现类并实现步骤1的接口
* */
public class PersionImpl implements Persion {
@Override
public void say() {
System.out.println("每个人都有说话的权力!");
}
}
步骤3:创建动态代理类JDKProxy.java
/**
* JDK动态代理步骤3
* -创建动态代理类
* */
public class JDKProxy {
private Persion persion;// 目标对象
// 构造函数
public JDKProxy(Persion _persion){
this.persion = _persion;
}
/**
* 给目标对象生成代理对象
*
* JDK中动态代理类只需要使用java.lang.reflect.Proxy.newProxyInstance方法,该方法需要接收三个参数,完整写法:
* static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
*
* ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
* Class<?>[] interfaces:目标对象实现的接口类型,使用泛型方式确认类型,获取接口类型的方法是固定的
* InvocationHandler h;事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
* */
public Object getProxyInstance(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),persion.getClass().getInterfaces(),this::invoke);
}
/**
* 生成执行目标对象方法
* */
public Object invoke(Object proxy, Method method, Object[] args){
try{
System.out.println("开始事务");
//执行目标对象方法
Object returnValue = method.invoke(persion, args);
System.out.println("结束事务");
return returnValue;
}catch (Throwable throwable){
throwable.getLocalizedMessage();
return null;
}
}
}
步骤4:实现代理方法
/**
* JDK动态代理步骤4
* -实现代理方法
*
* 测试jdk动态代理
* 代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理
* 接口中增加方法时只用在实现类中增加方法,不用修改代理类。
* */
public class JDKMain {
public static void main(String[] args) {
// 目标对象
Persion persion = new PersionImpl();
// 【原始的类型 class com.jwt.demo.jdkdl.PersionImpl】
System.out.println(persion.getClass());
// 给目标对象,创建代理对象
Persion jdkProxy = (Persion) new JDKProxy(persion).getProxyInstance();
// class $JDKProxy 内存中动态生成的代理对象
System.out.println(jdkProxy.getClass());
// 执行代理方法
jdkProxy.say();
}
}
运行结果:
三、cglib动态代理
步骤1:引入jar包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
步骤2:创建被代理的类UserDao.java
public class UserDao{
public void getUser() {
System.out.println("cglib动态代理:得到用户信息");
}
public void insertUser() {
System.out.println("cglib动态代理:添加用户");
}
}
步骤3:创建代理类CglibProxy.java
/**
* cglib动态代理
*
* */
public class CglibProxy implements MethodInterceptor {
//维护目标对象
private Object target;
public CglibProxy (Object target) {
this.target = target;
}
//给目标对象创建一个代理对象
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy
methodProxy) throws Throwable {
System.out.println("开始事务...");
//执行目标对象的方法
Object returnValue = method.invoke(target, objects);
System.out.println("提交事务...");
return returnValue;
}
}
步骤4:实现代理方法
public class CglibProxyMain {
public static void main(String[] args) {
//目标对象
UserDao target = new UserDao();
System.out.println(target.getClass());
// 给目标对象,创建代理对象
UserDao proxy = (UserDao) new Proxy03(target).getProxyInstance();
System.out.println(proxy.getClass());
proxy.getUser();//执行的是代理的方法
proxy.insertUser();
}
}
运行结果: