一、场景
明星的经纪人
二、实质
通过代理控制对对象的访问。可以详细控制访问某个(某类)对象的方法,在调用这个方法之前做前置处理,调用这个方法后做后置处理。
AOP的核心实现机制。
三、角色
抽象角色--定义代理角色和真实角色的公共对外方法
真实角色--实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。关注真正的业务逻辑。(相当于明星)
代理角色--实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法实现抽象方法,并可以附加自己的操作。将统一的流程控制放到代理角色中处理。
(相当于经纪人)
四、分类
静态代理(静态定义代理类)
动态代理(动态生成代理类)
JDK自带的动态代理
javassist字节码操作库实现
CGIB
ASM
五、示例
1、静态代理
案例一
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)。
延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。