定义
代理一个对象 ,在对象前或后添加功能
静态代理
普通代理
代理对象和被代理对象实现同一个接口,代理对象引入被代理对象并调用其中方法
实现
public interface People {
void run();
}
public class RealPeopel implements People {
@Override
public void run() {
System.out.println("我在跑");
}
}
public class ProxyPeople implements People {
public People people=null;
public ProxyPeople(People people){
this.people=people;
}
@Override
public void run() {
System.out.println("我是前置方法");
people.run();
System.out.println("我是后置方法");
}
}
public class Client {
public static void main(String[] args) {
ProxyPeople proxyPeople=new ProxyPeople(new RealPeopel());
proxyPeople.run();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7oH5o0pc-1624368339861)(C:\Users\25443\AppData\Roaming\Typora\typora-user-images\image-20210621171021342.png)]
强制代理
再被代理对象中定义要使用的代理对象,通过被代理对象得到代理对象,进行代理(非指定的代理类无效)
实现
动态代理
public interface People {
void run();
}
public class RealPeopel implements People {
ProxyPeople proxyPeople=null;
@Override
public void run() {
if (proxyPeople!=null){
System.out.println("我在跑");
}else {
System.out.println("请使用正确的代理");
}
}
public ProxyPeople getProxy(){
return proxyPeople=new ProxyPeople(this);
}
}
public class ProxyPeople implements People {
public People people=null;
public ProxyPeople(People people){
this.people=people;
}
@Override
public void run() {
System.out.println("我是前置方法");
people.run();
System.out.println("我是后置方法");
}
}
public class Client {
public static void main(String[] args) {
RealPeopel realPeopel = new RealPeopel();
realPeopel.run();
ProxyPeople proxy = realPeopel.getProxy();
proxy.run();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gQtf3YYq-1624368339865)(C:\Users\25443\AppData\Roaming\Typora\typora-user-images\image-20210621171916412.png)]
JDK动态代理
被代理类必须实现接口.
Handler类用于描述代理类的操作,必须事先InvocationHandler接口
public interface Subject {
void run();
}
public class RealSubject implements Subject {
public void run(){
System.out.println("我在跑");
}
}
public class Handler implements InvocationHandler {
//被代理对象
private Object target=null;
public Handler(Object o){
target=o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//可以再此处写各种代理操作
System.out.println("哈哈哈我被代理啦 我是"+method.getName());
return method.invoke(target,args);
}
}
public class DynamicProxy<T> {
//简单工厂返回代理对象
public static <T>T newproxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){
return (T) Proxy.newProxyInstance(classLoader,interfaces,handler);
}
}
public class ObjectDynamicProxy extends DynamicProxy {
//针对具体业务的动态代理
public static <T>T newProxyInstance(Object object){
ClassLoader classLoader = object.getClass().getClassLoader();
Class<?>[] interfaces = object.getClass().getInterfaces();
Handler handler = new Handler(object);
return (T) Proxy.newProxyInstance(classLoader,interfaces,handler);
}
}
//测试类
public class Client {
public static void main(String[] args) {
Subject subject = new RealSubject();
Subject proxy = ObjectDynamicProxy.newProxyInstance(subject);
proxy.run();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KEfOs1fX-1624368339867)(C:\Users\25443\AppData\Roaming\Typora\typora-user-images\image-20210621160539788.png)]
CGlib动态代理
被代理类不需要实现接口
jdk创建对象的速度远大于cglib,这是由于cglib创建对象时需要操作字节码。cglib执行速度略大于jdk,所以比较适合单例模式。另外由于CGLIB的大部分类是直接对Java字节码进行操作,这样生成的类会在Java的永久堆中。如果动态代理操作过多,容易造成永久堆满,触发OutOfMemory异常。spring默认使用jdk动态代理,如果类没有接口,则使用cglib。
//和Handler有点相似
public class CglibProxy implements MethodInterceptor {
// 根据一个类型产生代理类,此方法不要求一定放在MethodInterceptor中
public Object CreatProxyedObj(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
//继承被代理类
enhancer.setSuperclass(clazz);
//设置回调
enhancer.setCallback(this);
//生成代理类 在调用代理类中方法时会被我们实现的方法拦截器进行拦截
return enhancer.create();
}
//Cglib使用的是继承机制 代理对象继承了被代理对象。所以才可以代理
/**
*
* @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 {
System.out.println("我是前置方法");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("我是后置方法");
return invoke;
}
}
public class RealSubject {
public void run(){
System.out.println("我在跑");
}
}
public class Client {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
RealSubject o = (RealSubject) cglibProxy.CreatProxyedObj(RealSubject.class);
o.run();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tKG1K6Ir-1624368339869)(C:\Users\25443\AppData\Roaming\Typora\typora-user-images\image-20210621165912107.png)]