静态代理:在使用静态代理时,被代理对象(目标对象)与代理对象需要一起实现相同的接口或者是继承相同父类,因此要定义一个接口或抽象类.
例子:明星与经纪人之间就是被代理和代理的关系,明星出演活动的时候,明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)
代码:
抽象主题:
public interface ISong{
//公共抽象方法
void Sing();
}
真实主题:
//目标对象
public class JJ implements ISong{
@Override
public void Sing() {
System.out.println("林俊杰在唱歌....");
}
}
代理主题:
//代理对象
public class JJProxy implements ISong{
//持有目标对象的引用!
private JJ jj;
public JJProxy(JJ jj) {
super();
this.jj = jj;
}
@Override
public void Sing() {
System.out.println("林俊杰唱歌前的准备工作");
jj.Sing();
System.out.println("林俊杰唱歌后的收拾工作");
}
}
客户端测试:
public class Client {
public static void main(String[] args) {
ISong iSong; //面向接口编程:依赖倒转原则
iSong = new JJProxy(new JJ());
iSong.Sing();
/**
控制台输出:
林俊杰唱歌前的准备工作
林俊杰在唱歌....
林俊杰唱歌后的收拾工作
*/
}
}
优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展.
缺点: 因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.
而动态代理方式可以解决上面的问题
一:代理模式目的:就是为了对某个对象的增强
增强对象的手段
1.继承:被增强对象不能变,增强内容不能变
2.装饰者模式:被增强对象可变,增强内容不可变
3.动态代理:被增强对象可变,增强内容可变
所有使用装饰者模式的地方,都可以使用代理模式!
二:概述:
今天来学习一下代理模式,学习动态代理模式一般都是在框架中使用,如果不写框架,基本上使用不到,但为什么还要去学呢?目的是为了更好的理解框架内部的原理,strust1,struts2,spring中都有用到!
今天其实就是学习一下JDK中的动态代理(Proxy)
Object proxyObj = Proxy.newProxyInstance(ClassLoader loader,class[] interfaces,InvocationHandler h);
newProxyInstance的三个参数:
ClassLoader :把.class文件加载到内存,形成Class对象,怎么获取呢? Class对象里面有个getClassLoader(),所以先得到Class对象就行了
class[]:指定的接口数组
InvocationHandler :它是一个接口!里面只有一个invoke()方法,它的名字叫调用处理器,
其实无论你调用代理对象的什么方法,它都是在调用InvocationHandler的invoke()方法!
这个代码的含义:
在运行时动态的创建一组指定接口的实现类对象!(创建对象)
也就是说proxyObj 就是一个实现了interfaces里面的所有接口的实现类,至于它到底是什么类型我们不知道,我们只知道他是指定接口的实现类,而且它不会有.class文件,因为它是在运行的时候创建的!
示例代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface A{
void a();
}
interface B{
void b();
}
public class Client {
public static void main(String[] args) {
ClassLoader classLoader = Client.class.getClassLoader();
//这个proxyObj代理对象,就是实现了A和B接口!
Object proxyObj = Proxy.newProxyInstance(classLoader, new Class[]{A.class,B.class},new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("你好动态代理");
return null;
}
});
/**
* 既然说proxyObj代理对象是实现了A,B两个接口
* 疑问一:那么我想知道实现类具体是什么类型的!
* 疑问二:那么应该可以使用A,B接口中的方法
*/
System.out.println(proxyObj.getClass().getSimpleName());//$Proxy0,不知道什么类型,也不用管
System.out.println(proxyObj instanceof A); //true
System.out.println(proxyObj instanceof B); //true
//直接调用是Object类中的方法,所以我得强转一下,不管调用代理对象中的什么方法,都会去执行InvocationHandler中的invoke()方法!, 除了getClass();
A a = (A)proxyObj;
a.a();
a.toString();
}
}
invoke方法中的三个参数!
invoke(Object proxy, Method method, Object[] args)
proxy:表示代理对象
method:表示当前被调用方法的反射对象
args:表示当前被调用方法的参数
三:实例
目标对象:就是需要被增强的对象
代理对象:就是需要维护一个目标对象的引用,然后在目标对象上增强的对象
目标方法:增强的内容
代理对象 = 目标对象 + 增强!
动态代理中的角色:抽象主题,真实主题,代理主题
抽象主题
public interface Waiter {
void server();
}
真实主题
public class ManWaiter implements Waiter{
@Override
public void server() {
System.out.println("服务中....");
}
}
代理主题和测试代码!
public class Client {
public static void main(String[] args) {
Waiter waiter = new ManWaiter();//目标对象
ClassLoader classLoader = Client.class.getClassLoader();
Class[] interfaces = {Waiter.class};
InvocationHandler h = new WaiterInvocationHandler(waiter);
//代理对象:就是在目标对象的基础上进行增强了的对象!
Object proxyObj = Proxy.newProxyInstance(classLoader, interfaces,h);
//强转一下才能使用接口中的方法
Waiter w = (Waiter)proxyObj;
w.server();
}
}
class WaiterInvocationHandler implements InvocationHandler{
//维护一个目标对象的引用
private Waiter waiter;
public WaiterInvocationHandler(Waiter waiter) {
super();
this.waiter = waiter;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("你好");
this.waiter.server();
System.out.println("再见");
return null;
}
}
还有一个cglib代理:暂时不写