如何简单描述java中的代理模式

java里什么是代理

比如A是一个接口,B是被加强对象,C是代理对象

A接口有一个say()方法,B实现了A接口,C也实现了A接口,C在自己实现的say()方法里不但执行了B的say()方法也执行了一些自己的程序,这就是代理。

代理分为静态代理和动态代理。

为什么要代理

类的增强可以通过继承来实现,那如果想让某个方法增强呢?这时候就用到代理了。

如何代理?

大体上有目标类,代理类,增强(通知),连接点。

代理类在连接点处通过增强(通知)来对目标类进行增强。

我简单理解成增强就是在目标执行某方法进行拦截时执行的代码,拦截就是对方法或者参数进行分析,具体拦截后怎么做自己想怎么写就怎么写。

连接点是指那些被拦截到的点,大白话就是在哪些方法中拦截,总不能所有目标类的方法都拦截吧,只拦截我想要增强的方法就行了,在Spring中这些点指的是方法因为Spring只支持方法类型的连接点


静态代理的用途

控制真实对象的访问权限 通过代理对象控制对真实对象的使用权限。

避免创建大对象 通过使用一个代理小对象来代表一个真实的大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。

增强真实对象的功能 这个比较简单,通过代理可以在调用真实对象的方法的前后增加额外功能。


代理分为静态代理和动态代理

静态代理:

1、代理对象和目标对象都要实现的   公共接口

2、代理对象持有目标对象引用,重写构造方法,

3、实现共同的方法,代理对象增强行为。

缺点:

代理角色固定,一次只能代理一个对象。

接口

  1. public interface Marry {
    void marry();
    }
目标对象

  1. public class You implements Marry {
    public void marry() {
    System.out.println("sihai get marry");
    }
    }
代理对象
  1. public class MarryCompany implements Marry {
    private You you;
    public MarryCompany(You you) {
    this.you = you;
    }
    public void marry() {
    before();
    you.marry();
    after();
    }
    private void after() {
    System.out.println("get after work done");
    }
    private void before() {
    System.out.println("get ready for marry");
    }
    }
测试
  1. public class TestMarry {
    public static void main(String[] args) {
    You you = new You();
    MarryCompany marryCompany = new MarryCompany(you);
    marryCompany.marry();
    }
    }
结果
  1. get ready for marry
    sihai get marry
    get after work done

动态代理

根据需要通过反射机制在程序运行期动态的为目标对象创建代理对象,代理的行为可以代理多个方法,即满足生产需要的同时又达到代码的通用目的。


问题1.不能手动的为每一个目标都写代理。

那么多目标,一个一个写是不是太浪费时间了?

这时有两种解决方案:

(1)JDK的动态---运行过程代理,启动快执行慢,首选,必须接口实现,JDK动态代理的过程中,生成的动态代理对象与目标对象是同一接口实现
(2)CGLIB的动态代理---从字节级别代理,启动比JDK费时间但执行快,会为每一个目标类生成对应的子类

问题2.对于增强,不能写成硬编码

 硬编码是说写死的编码,增强的方法都写死固然会很繁琐


JDK的动态代理

实现JDK的动态代理有两部分最重要:

1.动态代理对象的生成(需要类加载器,实现接口类型,调用处理程序,源码这样写的)

2.调用处理程序(执行的增强方法)

举个栗子:

接口类

public interface DogI {
	void say();
}

目标类

public class Dog implements DogI{

	@Override
	public void say() {
		System.out.println("hello");
	}
	
}

动态生成代理对象的类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DogJDKPROXY implements InvocationHandler {
	//target为传进来的目标类
	private Object target;
	//获取传进来的目标类,并获取目标类的 类加载器,类接口,this指的是调用此方法的目标(还是目标类),需要实现InvocationHandler接口,重写invoke方法并执行
	public Object getProxyObject(Object target) {
		this.target=target;
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}
	
	//在这里可以进行拦截,加强之类的操作,我这里什么增强都没写
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//代理的类,执行的方法,传递的参数
		Object result = method.invoke(target, args);
		return result;
	}
}

测试

public class Test {
	public static void main(String[] args) {
		DogI dog =(DogI) new DogJDKPROXY().getProxyObject(new Dog());
		dog.say();
	}
}
JDK的动态代理是生成 目标类 接口对象 ,是接口对象!


CGLIB的动态代理

目标类

public class Person {
	public void say() {
		System.out.println("hello");
	}
}

动态生成代理对象的类

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class PersonCGLIBProxy implements MethodInterceptor{
	//target为传过来的目标类
	private Object target;
	//获取目标类,需要Enhancer对象获取目标类的,然后从字节码的级别创造代理对象,设置setCallback才能拦截(增强),把目标类放进去实现MethodInterceptor并重写intercept
	public Object getProxyObject(Object target) {
		this.target=target;
		Enhancer enhancer=new Enhancer();
		enhancer.setSuperclass(target.getClass());
		enhancer.setCallback(this);
		return enhancer.create();
	}
	
	//这个方法就是增强的地方,arg0为生成的代理对象,arg1传进来的需要增强的方法(这里默认目标类的方法都拦截了)
	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy methodProxy) throws Throwable {
		Object result=methodProxy.invoke(target, arg2);
		return result;
	}
}

测试

public class Test {
	public static void main(String[] args) {
		Person p = (Person) new PersonCGLIBProxy().getProxyObject(new Person());
		p.say();
	}
}

对比一下两者发现非常相似,都是传过来一个目标类,然后获取这个目标类的某些东西,然后创建一个代理类,如果代理类执行方法,就会通过一个固定的方法来获取这个方法以及这个方法的参数,然后在代理类的这个方法里进行一些处理。


但是:使用动态代理机制虽然解决了代理对象的生成问题,但是要为对象的哪个方法增强,以及增强应该如何实现等等,没有实现这样的功能,所以非常不灵活

为了解决这个方法,可以使用Spring的AOP解决。


动态代理的用途

Java的动态代理,在日常开发中可能并不经常使用,但是并不代表他不重要。Java的动态代理的最主要的用途就是应用在各种框架中。因为使用动态代理可以很方便的运行期生成代理类,通过代理类可以做很多事情,比如AOP,比如过滤器拦截器等。

在我们平时使用的框架中,像servlet的filter、包括spring提供的aop以及struts2的拦截器都使用了动态代理功能。我们日常看到的mybatis分页插件,以及日志拦截、事务拦截、权限拦截这些几乎全部由动态代理的身影。


总结:





猜你喜欢

转载自blog.csdn.net/bibiboyx/article/details/81025355