代理模式
代理模式,就是SpringAop的底层。【SpringAop和SpringMVC】
代理模式的分类
- 动态代理
- 静态代理
1静态代理
角色分析:
- 抽象角色:一般会使用抽象类或者接口来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理之后可以进行一些附属操作
- 客户:访问代理角色的人
优点:
- 真实角色的操作更加纯粹,不用关注公共业务
- 公共业务交给代理角色,实现了业务的分工。(出租房是房东的事情,现在由中介代替)
- 公共业务发生扩展时候,方便集中管理。
缺点:
- 一个真实角色就需要一个代理角色。真实角色多的时候,代码量会翻倍;
案例
- 接口
// 租房
public interface Rent{
public void rent(); //租房方法
}
- 真实角色
//房东,
public class Host implements Rent{
public void rent(){
System.out.println("房东要出租房子!");
}
}
- 代理角色
//代理角色 proxy
public class Proxy implements Rent{
private Host host;//将房东组合进来,
public Proxy(){}
public Proxy(Host host){
this.host=host
}
public void rent(){ //租房
seeHouse();
hrtong();
host.rent();
}
// 附属操作
public void seeHouse(){
System.out.println("中介带你看房!")
}
public void hetong(){
System.out.println("签租赁合同")
}
}
- 客户端访问代理角色
//客户端
public class Client {
public static void main(String[] args){
// 房东
Host host = new Host();
// 中介,中介代理房东
Proxy proxy = new Proxy(host);
//中介出租房
proxy.rent();
}
}
加深理解,在执行方法的时候添加日志
方法接口
public interface service{
public void add();
public void delete();
public void update();
public void query();
}
实现类
public class serviceImpl implements Service{
public void add(){
System.out.println("新增一个客户!")
}
public void delete(){
System.out.println("删除一个客户!")
}
public void update(){
System.out.println("更新一个客户!")
}
public void query(){
System.out.println("查询一个客户!")
}
}
客户端类
public class Client{
public static void main(String[] args){
ServiceImpl servieImpl = new ServiceImpl();
servieImpl.add();
}
}
新需求:给每个方法新增一个打印日志的方法
新增一个代理类
public class Proxy implements Service{
private ServiceImpl serviceImpl;
public void setServiceImpl(ServiceImpl serviceImpl){
return this.serviceImpl=serviceImpl;
}
public void add(){
log(add);
System.out.println("新增一个客户!")
}
public void delete(){
log(delete);
System.out.println("删除一个客户!")
}
public void update(){
log(update);
System.out.println("更新一个客户!")
}
public void query(){
log(query);
System.out.println("查询一个客户!")
}
//新增 日志方法
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
客户端类
public class Client{
public static void main(String[] args){
ServiceImpl serviceImpl = new ServiceImpl();
Proxy proxy = new Proxy();
proxy.setServiceImpl(serviceImpl);
proxy.add();
}
}
2 动态代理
动态代理的底层是反射。
动态代理和静态代理的角色一样。动态代理的类是动态生成的
动态代理分类:
- 基于接口的动态代理:JDK代理【案例使用这种方法】
- 基于类的动态代理:cglib,现在用的比较多的是 Java字节码:javassist
优点:
- 真实角色的操作更加纯粹,不用关注公共业务
- 公共业务交给代理角色,实现了业务的分工。(出租房是房东的事情,现在由中介代替)
- 公共业务发生扩展时候,方便集中管理。
- 一个动态代理代理的是一个接口,一般是这一类业务
- 一个动态代理可以代理多个类,只要实现的是同一个接口即可。(只要实现了租房接口,其他的不用改,只需要将客户端类中的真实角色修改即可。)
案例
- 接口
//租房
public class Rent{
public void rent();
}
- 真实角色
//房东,
public class Host implements Rent{
public void rent(){
System.out.println("房东要出租房子!");
}
}
- 代理角色
//代理
public class ProxyInvocationHandler implements InvocationHandler{
//被代理的类
private Rent rent;
public void setRent(Rent rent){
this.rent = rent;
}
//生成 得到的代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterface(),this);
}
// 处理代理实例,并返回结果。 调用代理的执行方法
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
//动态代理的本质就是使用反射机制
seeHouse();
Object result = method.invoke(rent,args);
return result;
}
public void seeHouse(){
System.out.println("中介带你看房");
}
}
- 客户端
public class Client{
public static void main(String[] args){
// 真实角色
Host host = new host();
//代理角色,这里不存在
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口对象
pih.setRent(host);
// proxy就是动态生成的代理
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
加深理解,在执行方法的时候添加日志
方法接口
public interface service{
public void add();
public void delete();
public void update();
public void query();
}
实现类
public class serviceImpl implements Service{
public void add(){
System.out.println("新增一个客户!")
}
public void delete(){
System.out.println("删除一个客户!")
}
public void update(){
System.out.println("更新一个客户!")
}
public void query(){
System.out.println("查询一个客户!")
}
}
动态代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target; // Object类,接收类型,这个方法这个定义为一个工具类的写法/模板类的写法
public void setTarget(Object target){
return this.target=target;
}
// 生成得到的代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader,target.getClass().getInterface(),this);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy,Method method,Object[] args){
Object result = method.invoke(target,args);
return result;
}
}
客户端
public class Client{
public static void main(Stirng[] args){
//真实角色
ServiceImpl serviceImpl = new ServiceImpl();
//代理角色。只是被创建,还没初始化。
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//设置代理对象
pih.setTarget(serviceImpl);
//创建代理对象,动态生成代理类
ServiceImpl proxy = (ServiceImpl)pih.getProxy();
proxy.add();
}
}
新需求:给每个方法新增一个打印日志的方法
这里是动态代理,不需要新建一个代理类,修改原 动态代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target; // Object类,接收类型,这个方法这个定义为一个工具类的写法/模板类的写法
public void setTarget(Object target){
return this.target=target;
}
// 生成得到的代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader,target.getClass().getInterface(),this);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy,Method method,Object[] args){
log(method.getName());
Object result = method.invoke(target,args);
return result;
}
public void log(String args){
System.out.println("执行了"+args+"方法")
}
}