代码参考(更详细,这里为了博客简洁,代码去了一些注释) github.com/zhang-xiaox…
1静态代理(接口代理)
需求(干什么):对明星唱歌的业务流程进行代理,而明星唱歌还是交由明星自己唱歌,这个流程把唱歌分成2部分了,1:歌手尽管唱歌,2:代理公司负责打杂(面谈,签合同,订票,收钱),对被代理的歌手来说,他解放了,相当于增强了,不用自己面谈,签合同什么的,对代理公司来说,我就打杂就行了,赚点差价,唱歌不行,只好请歌手(无法全程代理),各司其职.
先明确所有流程下来需要干那些事情,使用接口明确一下(面向接口编程哈)
package com.demo.proxy.staticproxy;
/**
* Star:代理接口,这里规定了整个业务需要完成的事情
* (万事万物接口开头,面向接口编程,先明确要干什么,怎么干是后面实现类的事情,这样有利于解耦,
* 比如同样是面谈的实现,需要换个面谈方式那不是还得修改代理类?这里直接定义成接口,那么代理要换个代理只需要换个代理实现类就行了
* 不需要对代理接口进行修改,达到开闭原则,开放拓展,但是修改接口这个代理接口Star不允许)
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public interface Star {
/**
* 面谈
*/
void confer();
/**
* 签合同
*/
void signContract();
/**
* 订票
*/
void bookTicket();
/**
* 唱歌
*/
void sing();
/**
* 收钱
*/
void collectMoney();
}
知道了要干什么(上面接口明确了),但是怎么干(实现类)呢,先来个歌手独立开一场演唱会就需要实现所有接口,又当爹又当妈
//package com.demo.proxy.staticproxy;
/**
* RealStar:一个真实的歌手,在没有代理的情况下需要全部实现,又当爹又当妈
* (显然不不合理,对歌手来说,除了唱歌,其他打杂的事情,面谈,签合同什么的都没有必要去做)
*
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class RealStar implements Star {
/**
* 面谈
*/
@Override
public void confer() {
//可以做空实现
System.out.println("真实对象执行面谈===>RealStar.confer()");
}
/**
* 签合同
*/
@Override
public void signContract() {
//可以做空实现
System.out.println("真实对象执行签合同===>RealStar.confer()");
}
/**
* 订票
*/
@Override
public void bookTicket() {
//可以做空实现
System.out.println("真实对象执行订票===>RealStar.confer()");
}
/**
* 唱歌---歌手主要唱歌,其他事情(具体实现),可以不做(就是空实现)
*/
@Override
public void sing() {
//这里唱歌是必须实现的,不然算什么歌手
System.out.println("真实对象(周杰伦)执行唱歌===>RealStar.confer()");
}
/**
* 收钱
*/
@Override
public void collectMoney() {
//可以做空实现
System.out.println("真实对象执行收钱===>RealStar.confer()");
}
}
上面真实歌手在吐槽又当爹又当妈,我作为天使,肯定是来解救你的,并且我不抢你唱歌的光彩,你唱你的,我给你打杂就行了,赚点差价哈哈,下面就是我的自我介绍
//package com.demo.proxy.staticproxy;
/**
* ProxyStar:代理对象,这是个对某个类(对象)进行增强的
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class ProxyStar implements Star {
/**
* 专业的事情教给专业的人去做,比如在这里就是相当于请歌手唱歌
* 注意这里接口做属性,组合比实现类(应用)做属性好的多,因为接口做属性可以请很多歌手唱歌(提现多态),
* 但是是实现类做属性(面向实现编程)耦合度太高,换个歌手又得修改这个类,开闭原则是尽量不要修改这个类,所以这里
* 是使用Star,而不是 private RealStar star
* ---静态代理代理的是接口就是出自这里
*/
private Star star;
/**
* 怎么请?这里使用构造方法请,用set方法也行
* @param star
*/
public ProxyStar(Star star) {
this.star = star;
}
/**
* 面谈---代理对象专业的人处理其他事情,相当于打杂,对专业的人来说,相当于增强了
*/
@Override
public void confer() {
System.out.println("代理面谈===>ProxyStar.bookTicket()");
}
/**
* 签合同---代理对象专业的人处理其他事情,相当于打杂,对专业的人来说,相当于增强了
*/
@Override
public void signContract() {
System.out.println("代理签合同===>ProxyStar.bookTicket()");
}
/**
* 订票---代理对象专业的人处理其他事情,相当于打杂,对专业的人来说,相当于增强了
*/
@Override
public void bookTicket() {
System.out.println("代理订票===>ProxyStar.bookTicket()");
}
/**
* 唱歌===专业的人做专业的事
*/
@Override
public void sing() {
System.out.println("*******代理对象不抢主角光环*******");
star.sing();
}
/**
* 收钱---代理对象专业的人处理其他事情,相当于打杂,对专业的人来说,相当于增强了
*/
@Override
public void collectMoney() {
System.out.println("代理收钱===>ProxyStar.bookTicket()");
}
}
牛皮都吹出去了,测试一下呗,合作愉快下次继续哟,亲,记得给个五星好评哟
package com.demo.proxy.staticproxy;
/**
* Client:客户端 静态代理测试
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class Client {
public static void main(String[] args) {
System.out.println("----------------------测试静态代理-------------------");
Star real = new RealStar();
Star proxy = new ProxyStar(real);
proxy.confer();
proxy.signContract();
proxy.bookTicket();
//这里代理对象持有真实对象的一切,比如让代理的真实对象周杰伦唱歌,对周杰伦这个对象来说,他功能增强了,
//上面的操作和下面的操作都算增强
proxy.sing();
proxy.collectMoney();
}
}
演唱会全程回顾如下:
2动态代理(代理对象) Star接口还是那个接口(上文静态代理的),RealStar接口还是那个接口(上文静态代理的)
一个对JDK调用处理器的实现类
//package com.demo.proxy.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* StarHandler:这是一个对JDK调用处理器的实现类,用于被代理的一个类,利用这个类可以JDK为其生成一个代理对象
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class StarHandler implements InvocationHandler {
/**
* 这里仍然是要代理接口的,相当于唱歌业务流程始终是要有公司接单,实现演唱会,只是这里不是代理类直接接单
* 由评审团StarHandler来评估先代理
*/
Star realStar;
/**
* 构造方法注入"演唱会订单"
* @param realStar
*/
public StarHandler(Star realStar) {
this.realStar = realStar;
}
/**
* 重写JDK代理方法(使用反射生成响应对象)
* @param proxy 评估后具备代理资格的代理公司对象
* @param method 方法(真是对象需要执行的操作,唱歌)
* @param args
* @return
* @throws Throwable
*/
@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.demo.proxy.dynamicproxy;
/**
* ProxyStar:模拟动态生成的代理的类
*
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class ProxyStar implements Star {
/**
* 注入代理处理器类(动态代理是代理类这句话,就是来自这里),在静态代理这里是直接注入的private Star star 接口,就是代理的是接口
* ---一句话代理类,这个类是动态的哈
*/
StarHandler handler;
/**
* 使用构造方法实现注入,set方法也行,不赘述
*
* @param handler
*/
public ProxyStar(StarHandler handler) {
this.handler = handler;
}
/**
* 面谈
*/
@Override
public void confer() {
// handler.invoke(this,当前方法 , args);
}
/**
* 签合同
*/
@Override
public void signContract() {
// handler.invoke(this,当前方法 , args);
}
/**
* 订票
*/
@Override
public void bookTicket() {
// handler.invoke(this,当前方法 , args);
}
/**
* 唱歌
*/
@Override
public void sing() {
// handler.invoke(this,当前方法 , args);
}
/**
* 收钱
*/
@Override
public void collectMoney() {
// handler.invoke(this,当前方法 , args);
}
}
客户端测试
package com.demo.proxy.dynamicproxy;
import java.lang.reflect.Proxy;
/**
* Client:客户端 测试动态代理
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class Client {
public static void main(String[] args) {
System.out.println("----------测试的动态代理-----------");
Star realStar = new RealStar();
//代理类
StarHandler handler = new StarHandler(realStar);
//利用JDK生成代理对象
Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Star.class}, handler);
proxy.sing();
}
}
动态代理的演唱会事故现场
3:cglib代理,请参考www.cnblogs.com/boboxing/p/…
总结:AOP面向切面编程早晚会用的一种模式,自己去体会3个模式的优缺点,然后瞎搞几下.