动态代理的三种实现方式

代理模式

代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.

简单来说就是说代理就是增强方法,让方法实现更多的额功能

举个栗子:

你过生日想邀请laddygaga来给你唱歌,可是laddygaga不认识你,你也联系不到他,这样你可以通过他的经纪人,来间接和laddygaga进行交流。要做什么,对方要多少钱,都是和经纪人商量。这就是一个代理模式。经纪人就是一个代理。

1,静态代理

针对于网上大多数静态代理写成装饰者模式(装饰着模式和静态代理的区别https://blog.csdn.net/weixin_35609314/article/details/78913635),做了一下总结:

1,被代理的对象必须是一个类,且必须有父接口或者父类;

2,被代理的类需要增强的方法必须在父类或者父接口中出现;

3,静态代理的使用目的是为了保护和隐藏目标对象,所以代理类的无参构造器中就创建目标对象。

interface Perple {
	public void learn();
}
class Student implements Perple {
	public Student() {
		super();
	}
	@Override
	public void learn() {
		System.out.println("Students learning mathematics");
	}
}
class UniversityStudent implements Perple {
	Perple perple;
	public UniversityStudent() {
		this.perple = new Student();
	}
	@Override
	public void learn() {
		this.perple.learn();
		System.out.println("University student studying advanced mathematics");
	}
}

缺点:

1,因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多

2,如果代理对象实现的是接口,父接口中增加方法,目标对象与代理对象都要维护

动态代理方式可以解决上述缺点

2,动态代理

也叫jdk代理,java底层封装了实现细节,格式固定,代码简单。直接调用java.lang.reflect.Proxy的静态方法newProxyInstance即可

1,被代理的对象必须是一个类,且必须有父接口;

2,被代理的类需要增强的方法必须在父接口中出现;

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

参数:

1,ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的

2,Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型

3,InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入

public class DynamicProxy {
	public static void main(String[] args) {
		Singer singer = new Singer();
		Object newProxyInstance = java.lang.reflect.Proxy.newProxyInstance(
                    singer.getClass().getClassLoader(),
		    singer.getClass().getInterfaces(),
                     (proxy, method, ar) -> {
					System.out.println("22222");
					method.invoke(singer, args);
					System.out.println("3333");
					return null;
				});
		ISinger i = (ISinger) newProxyInstance;
		i.sing();
	}
}
class Singer implements ISinger {
	public void sing() {
		System.out.println("sing");
	}
}
interface ISinger {
	public void sing();
}

上述:    (proxy, method, ar) -> {
                    System.out.println("22222");
                    method.invoke(singer, args);
                    System.out.println("3333");
                    return null;
                });

是java8的lambda表达式等于 

new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("22222");
                        method.invoke(singer, args);
                        System.out.println("3333");
                        return null;
                    }
                }

注意:代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理。但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理

3.Cglib代理

Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.

1,Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)

2,Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.

1,被代理的类

public class TargetProxy {
	public void save() {
		System.out.println("假如这个是Spring的service层的方法");
	}
}

2,代理对象

public class ProxyFactory implements MethodInterceptor {
	private Object target;

	public ProxyFactory(Object target) {
		this.target = target;
	}

	// 给目标对象创建一个代理对象
	public Object getProxyInstance() {
		Enhancer en = new Enhancer();
		en.setSuperclass(target.getClass());
		en.setCallback(this);
		return en.create();
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("开始事务...");
		Object returnValue = method.invoke(target, args);
		System.out.println("提交事务...");
		return returnValue;
	}
}

3,测试app

public class App {
	public static void main(String[] args) {
		// 目标对象
		TargetProxy target = new TargetProxy();
		ProxyFactory factory = new ProxyFactory(target);
		target = (TargetProxy) factory.getProxyInstance();
		// 执行代理对象的方法
		target.save();
	}

}

需要导入的包

猜你喜欢

转载自blog.csdn.net/nimqbiyq/article/details/81166893