一、定义
1、 什么是代理模式?
为其他对象提供一种代理以控制对这个对象的访问。(就是用用一个中间者,让被代理的对象能够访问其他对象。)
实例:就像房产中介就是代理对象,买房的你就是被代理对象,卖房则为其他对象。买房的你被代理,只需要实现交钱手续,其他的小手续则有房产中介为你代劳。
2、UML图
二、实例
1、静态代理
静态代理要求被代理类和代理类实现同一个接口或者类。
重点:在编译期间确定代理对象,在程序运行前就已经确定代理类.class文件已经存在。比如:代理对象实例化时,通过代理对象类的构造方法将被代理对象传入。
譬如:(静态代理这段代码很像装饰者模式)
接口:User
package com.golf.proxy;
//代理类和被代理类的公共接口
public interface User {
public void save();
}
被代理类:UserDao
package com.golf.proxy;
//代理类和被代理类的公共接口
public interface User {
public void save();
}
代理类:ProxyUser
package com.golf.proxy;
//代理类
public class ProxyUser implements User{
public User user;
public ProxyUser(User user){ //通过构造方法将
this.user = user;
}
@Override
public void save() {
System.out.println("开始事务");
user.save();
System.out.println("结束事务");
}
}
静态代理的总结:
优点:可以在不更改原有类的基础上,增加功能。符合开放-封闭原则。(感觉贼像装饰者模式)
缺点:
代理类和被代理类实现相同的接口,会让代码重复很多。同时,如果接口增加一个新的方法,代理类和被代理类都需要实现这个方法,代码的维护变得复杂。
2、动态代理(JDK代理)
1、动态代理的代理类不需要实现接口。
2、代理对象的生成是通过JDK的API动态的在内存中构建对象(通过构造方法,将指定的被代理对象传入。通过JDK的代理类所在的包Java.lang.reflect.Proxy)
3、动态代理只需要实现newProxyInstance方法。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
该方法是静态方法,在对应的ProxyFactory中,导入JDK的Proxy类然后直接调用变形。
三个参数分别代表的意义
1、ClassLoader loader : 被代理类的对象。 被代理对象.getClass().getClassLoader();获得被代理对象
2、Class<?> interface : 是公共的接口。 公共接口.getClass().getInterface() 获得接口
3、InvocationHandler h:调用处理器
在动态代理中,除了代理类不同其他的都一样,被代理类一样需要实现接口。在动态代理中,创建ProxyFactory类,在通过JDK的newProxyInstance方法去创建对应的代理类。
package com.golf.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态创建代理对象
//动态代理对象无需实现公共接口,根据jdk的api在内存中创建相应的被代理对象
public class ProxyFactory {
public User user;
public ProxyFactory(User user){ //通过构造方法将被代理类传入
this.user = user;
}
//此方法用Object进行返回,不清楚代理类最后返回的类型,记得在客户端中相应的转换。
public Object getInstanceProxy(){
return Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始事务");
Object invoke = method.invoke(user, args);
System.out.println("结束事务");
return invoke;
}
}
);
}
}
测试类:
package com.golf.proxy;
public class ClientProxy {
public static void main(String[] args) {
User user = new UserDao();
ProxyFactory proxyFactory = new ProxyFactory(user);
//proxyFactory类的getInstance方法 返回的是Object型,需要根据自己被代理类的类型进行转换
User instanceProxy = (User)proxyFactory.getInstanceProxy();
System.out.println(instanceProxy.getClass());
instanceProxy.save();
}
}
动态代理的好处:
相对于静态代理而言,动态代理的代理类无需实现接口,但是被代理类需要实现接口。
3、Cglib代理
Cglib代理的好处在于他不需要代理类和被代理类实现接口,只是一个单独的对象。通过构建被代理类子类的方式实现代理。
定义:Cglib代理(子类代理),在内存中构建一个子类对象从而实现对代理对象功能的扩展。
注意点:
1、需要用到Cglib包,Spring-Core的包已经整合,所以只需要导入Spring-Core包就行。
2、Cglib是一个强大的高性能代码生成包,他可以在运行期扩展Java类和实现Java接口,在Spring框架AOP里面有进行使用,提供方法的Interception(拦截)。
3、Cglib包的底层通过字节码处理框架ASM来转换字节码生成新的子类。
4、被代理的类不能被final修饰,被代理类的方法如果被final、static所修饰便不会被拦截器拦截,因此也不会生效。
package com.golf.CglibProxy;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
//对UserDao在内存中动态的创建了一个子类对象
//代理工厂类
public class ProxyFactory implements MethodInterceptor{
private UserDao userDao; //被代理对象
public ProxyFactory(UserDao userDao){
this.userDao = userDao;
}
//创建一个代理对象
public Object getInstance(){
//1、导入JDK中Enhancer工具类
Enhancer enhancer = new Enhancer();
//2、设置父类
enhancer.setSuperclass(userDao.getClass());
//3、设置回调函数
enhancer.setCallback(this);
//4、创建代理对象(子类)
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开始事务");
Object invoke = method.invoke(userDao, objects);
System.out.println("结束事务");
return invoke;
}
}
测试类:
/**
* 测试类
*/
public class App {
@Test
public void test(){
//目标对象
UserDao target = new UserDao();
//代理对象
UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();
//执行代理对象的方法
proxy.save();
}
}
ps:由于是新学设计模式,很多的知识借鉴他人,可能有些观点很可怜。若有错误,希望指出!谢谢!!