一、场景

明星的经纪人

二、实质

通过代理控制对对象的访问。可以详细控制访问某个(某类)对象的方法,在调用这个方法之前做前置处理,调用这个方法后做后置处理。

AOP的核心实现机制。

三、角色

抽象角色--定义代理角色和真实角色的公共对外方法

真实角色--实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。关注真正的业务逻辑。(相当于明星)

代理角色--实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法实现抽象方法,并可以附加自己的操作。将统一的流程控制放到代理角色中处理。

(相当于经纪人)

四、分类

静态代理(静态定义代理类)

动态代理(动态生成代理类)

JDK自带的动态代理

javassist字节码操作库实现

CGIB

ASM

五、示例

1、静态代理

设计模式学习笔记---代理模式Proxy(Java版)_目标对象

案例一

package com.lgd.proxy;

public interface Star {
void confer();//面谈
void signContract();//签合同
void bookTicket();//订票
void sing();//唱歌
void collectMoney();//收钱
}



package com.lgd.proxy;

public class RealStar implements Star{

@Override
public void confer() {
System.out.println("realstar.confer()");
}

@Override
public void signContract() {
System.out.println("realstar.signContract()");
}

@Override
public void bookTicket() {
System.out.println("realstar.bookTicket()");
}

@Override
public void sing() {
System.out.println("realstar(@@@beyond@@@).sing()");
}

@Override
public void collectMoney() {
System.out.println("realstar.collectMoney()");
}

}




package com.lgd.proxy;

public class ProxyStar implements Star{
private Star star;

public ProxyStar(Star star) {
super();
this.star = star;
}

@Override
public void confer() {
System.out.println("proxystar.confer()");
}

@Override
public void signContract() {
System.out.println("proxystar.signContract()");
}

@Override
public void bookTicket() {
System.out.println("proxystar.bookTicket()");
}

@Override
public void sing() {
star.sing();
}

@Override
public void collectMoney() {
System.out.println("proxystar.collectMoney()");
}

}



package com.lgd.proxy;

public class Client {
public static void main(String[] args) {
Star realStar = new RealStar();
Star proxyStar = new ProxyStar(realStar);
proxyStar.confer();
proxyStar.signContract();
proxyStar.bookTicket();
proxyStar.sing();
proxyStar.collectMoney();
}
}



运行结果:

proxystar.confer()

proxystar.signContract()

proxystar.bookTicket()

realstar(@@@beyond@@@).sing()

proxystar.collectMoney()



案例二

package Thread;

/**
* 静态代理设计模式
* 1、真实角色
* 2、代理角色 持有真实角色的引用
* 3、二者要实现相同的接口
*/
public class Demo02 {
public static void main(String[] args) {
//创建真实角色
You you = new You();
//创建代理角色 + 加入真实角色的引用
WeddingCompany company = new WeddingCompany(you);//
//执行任务
company.marry();
}
}

//接口
interface Marry
{
public abstract void marry();
}

//真实角色
class You implements Marry{
@Override
public void marry() {
System.out.println("今天你要嫁给我。。。");
}
}

//代理角色
class WeddingCompany implements Marry{
private Marry you;

public WeddingCompany() {
}
public WeddingCompany(Marry you) {
super();
this.you = you;//使用真实角色对其初始化
}
private void before(){
System.out.println("婚前布置会场");
}

private void after(){
System.out.println("婚后打扫清洁");
}

@Override
public void marry() {
before();
you.marry();
after();
}
}



运行结果:

婚前布置会场

今天你要嫁给我。。。

婚后打扫清洁



静态代理的特点


优点:

可以做到在不修改目标对象的功能前提下,对目标对象功能扩展。


缺点:

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

一旦接口增加方法,目标对象与代理对象都要维护。


解决:

代理工厂?  可以使用动态代理。




2、动态代理(dynamic proxy)


1)代理对象,不需要实现接口;

2)代理对象的生成,是利用JDK API, 动态的在内存中构建代理对象(需要我们指定创建 ​代理对象/目标对象​ 实现的接口的类型;);

3)  动态代理也叫JDK代理或 接口代理;

JDK自带的动态代理

java.lang.reflect.Proxy  作用:动态生成代理类和对象。

java.lang.reflect.InvocationHandler(处理器接口)  通过invoke方法对真实角色的代理访问。每次通过Proxy生成代理类对象时都要制定对应的处理器对象。


实例一:

package com.lgd.dynamicproxy;

public interface Star {
void confer();//面谈
void signContract();//签合同
void bookTicket();//订票
void sing();//唱歌
void collectMoney();//收钱
}



package com.lgd.dynamicproxy;

public class RealStar implements Star{

@Override
public void confer() {
System.out.println("realstar.confer()");
}

@Override
public void signContract() {
System.out.println("realstar.signContract()");
}

@Override
public void bookTicket() {
System.out.println("realstar.bookTicket()");
}

@Override
public void sing() {
System.out.println("realstar(@@@beyond@@@).sing()");
}

@Override
public void collectMoney() {
System.out.println("realstar.collectMoney()");
}

}



package com.lgd.dynamicproxy;

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

public class StarHandler implements InvocationHandler{

Star realStar;

public StarHandler(Star realStar) {
super();
this.realStar = realStar;
}

/**
* 核心方法 做统一的流程控制
* 代理类的任何方法都来这里报到。
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object object = null;
System.out.println("真正的方法执行前!");
System.out.println("面谈,签合同,预付款,订机票");
if(method.getName().equals("sing"))
{
object = method.invoke(realStar, args);
}
System.out.println("真正的方法执行后!");
System.out.println("收钱");
return object;
}

}



package com.lgd.dynamicproxy;

import java.lang.reflect.Proxy;

public class Client {
public static void main(String[] args) {
Star realStar = new RealStar();
StarHandler handler = new StarHandler(realStar);

Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Star.class}, handler);
//proxy.bookTicket();
proxy.sing();
}
}




运行结果:

真正的方法执行前!

面谈,签合同,预付款,订机票

realstar(@@@beyond@@@).sing()

真正的方法执行后!

收钱



实例二

public interface IUserDao {

public void save();

}



public class UserDao implements  IUserDao {
@Override
public void save() {
System.out.println("目标对象save方法");
}
}



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

/**
* Created by liguodong on 2015/11/10.
*/
public class ProxyFactory {

//维护一个目标对象
private Object target;

public ProxyFactory(Object target){
this.target = target;
}
//给目标对象生成代理对象
public Object getFactoryInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开启事务");
//执行目标对象
Object returnValue = method.invoke(target,args);
System.out.println("开启事务");
return returnValue;
}
});
}
}




public class Main {

public static void main(String[] args) {
//目标对象
IUserDao target = new UserDao();
System.out.println(target);
//给目标对象创建代理对象
IUserDao proxy = (IUserDao) new ProxyFactory(target).getFactoryInstance();

proxy.save();
}
}



运行结果:

UserDao@19ce060

开启事务

目标对象save方法

开启事务


动态代理总结:

代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理。




六、应用场景

安全代理:屏蔽对真实角色的直接访问。

远程代理:通过代理类处理远程方法调用(RMI)。

延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。