代理模式(Proxy Pattern)
指为其他对象提供一种代理,以控制对这个对象的访问。
代理对象在客服端和目标对象之间起到中介作用
属于结构型设计模式。
适用场景:保护目标对象,增强目标对象
静态代理:显示声明被代理对象
动态代理:动态配置和替换被代理对象
无法代理final修饰的方法
静态代理
代理类与被代理类属于(1:1)一对一的关系,被代理类新增了某个方法,代理类也需要进行相应的修改,不符合开闭原则。
public interface Person {
void saleHouse();
void getName();
}
public class HousHolder implements Person {
@Override
public void saleHouse() {
System.out.println("houseHolder sale house");
}
@Override
public void getName() {
System.out.println("the name of house");
}
}
public class HouseSaler implements Person {
private HousHolder housHolder;
public HouseSaler(HousHolder housHolder) {
this.housHolder = housHolder;
}
@Override
public void saleHouse() {
System.out.println("HouseSaler sale house for houseHolder!===begin");
this.housHolder.saleHouse();
System.out.println("HouseSaler sale house for houseHolder!===end");
}
@Override
public void getName() {
System.out.println("the name of house saled by HouseSaler!===begin");
this.housHolder.getName();
System.out.println("the name of house saled by HouseSaler!===end");
}
}
public class HouseTest {
public static void main(String[] args) {
HouseSaler houseSaler = new HouseSaler(new HousHolder());
houseSaler.saleHouse();
houseSaler.getName();
}
}
结果输出为:
HouseSaler sale house for houseHolder!===begin
houseHolder sale house
HouseSaler sale house for houseHolder!===end
the name of house saled by HouseSaler!===begin
the name of house
the name of house saled by HouseSaler!===end
动态代理
实现原理:
1、拿到被代理类的引用,并获取它的所有的接口(反射获取)。
2、JDK Proxy 类重新生成一个新的类,实现了被代理类所有的接口的方法。
3、动态代理生成Java代理,把增强逻辑加入到新生成的代码中。
4、编译生成新的Java代码的class文件。
5、加载并重新运行新的class,得到的类就是全新的类。
优点:能将代理对象与真实被调用的目标对象分开;降低了系统的耦合程度,易于扩展;保护了目标对象;增强了目标对象的职责;
缺点:会增加系统设计中类的数目;在客户端与被代理对象之间增加了一个代理对象,会造成请求处理速度变慢;增加系统的复杂度;
用途:动态代理用于实现AOP编程,可以在不修改类源码,在类方法执行的前后添加其他的操作,如:拦截处理,日志打印....
JDK Proxy示例:
注意:被代理的类必须实现接口,用于JDK Proxy 重新生成的类实现其接口的所有方法
public interface Person {
void saleHouse();
void getName();
}
public class HouseHolder implements Person {
public HouseHolder() {
}
public void saleHouse() {
System.out.println("房屋持有者卖房");
}
@Override
public void getName() {
System.out.println("get houser name");
}
}
public class SalerMedia<T> implements InvocationHandler {
private T person;
public Object getInstance(T person) {
this.person = person;
Class<?> clazz = person.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(person, args);
}
}
public class HouseSaleTest {
public static void main(String[] args) {
Person person = (Person)new SalerMedia().getInstance(new HouseHolder());
person.saleHouse();
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[] {Person.class});
try {
FileOutputStream outputStream = new FileOutputStream("D:\\personPackage\\gupao\\$Proxy0.class");
outputStream.write(bytes);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试输出结果为:
房屋持有者卖房
HouseHolder 为被代理对象,实现了接口类(Person);
SalerMedia 为代理类,实现了InvocationHandler 接口,通过调用getInstance(T object)方法,JDK动态生成代理类$Proxy0,
调用$Proxy0.saleHouse(),会执行代理类SalerMedia的invoke(.....)方法,实现代理。
反编译生成的$proxy.class 文件:
public final class $Proxy0 extends Proxy
implements Person
{
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void getName()
{
try
{
super.h.invoke(this, m3, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void saleHouse()
{
try
{
super.h.invoke(this, m4, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m3 = Class.forName("com.tealala.pattern.proxy.Person").getMethod("getName", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("com.tealala.pattern.proxy.Person").getMethod("saleHouse", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
CGLib动态代理
通过生成被代理类的【子类】实现代理,所以 Cglib是无法代理final修饰的方法或类
public interface Person {
void saleHouse();
void getName();
}
public class HouseHolder implements Person {
@Override
public void saleHouse() {
System.out.println("CGLib houseHolder sale house");
}
@Override
public void getName() {
System.out.println("CGLib the name of house");
}
}
public class HouseSaler implements MethodInterceptor {
//相当于Proxy,代理的工具类
Enhancer enhancer = new Enhancer();
public Object getInstance(Class<?> clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object o1 = methodProxy.invokeSuper(o, objects);
after();
return o1;
}
public void before() {
System.out.println("CGLib begin");
}
public void after() {
System.out.println("CGLib end");
}
}
public class CGLibTest {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\personPackage\\gupao");
Person person = (Person)new HouseSaler().getInstance(HouseHolder.class);
person.getName();
person.saleHouse();
}
}
执行结果:
CGLIB debugging enabled, writing to 'D:\personPackage\gupao'
CGLib begin
CGLib the name of house
CGLib end
CGLib begin
CGLib houseHolder sale house
CGLib end
来源:CSDN
作者:tealala
链接:https://blog.csdn.net/tealala/article/details/103479510