代理分类:
1.静态代理
2.动态代理
业务场景:
假设程二狗想买一台小米手机,陈雪峰正好开了一家手机专卖店买,程二狗通过陈雪峰的手机专卖店买到小米公司生产的手机,而不是去小米的总部去购买。(小米总部的责职只是负责生产小米手机)
在这个过程中,程二狗想买小米手机,是发出行为的人,是被代理的人,但是他并没有实际去做这件事情,而是把这件事交给陈雪峰来帮他完成;陈雪峰替程二狗买到了手机,是中间人,是代理人,他替程二狗完成了这件事,是代理人。
-------这就是静态代理:代理类(陈雪峰)和目标对象(被代理类)(程二狗)的类都是程序在编译期间就确定下来的,不利于程序的扩张,同时,每一个代理类只能为一个接口服务(陈雪峰就只能替别人买手机,其它的事情都做不了),这样一来程序在开发中必然产生过多的代理类
突然有一天,陈雪峰NB了,他什么事情都能代替陈二狗做,不管陈二狗要买手机、还是要买房、还是办证啥的,只要陈二狗提出相应的需求,他都能帮陈二狗完成。
--------这就是动态代理:就好比陈雪峰开了一家店,能满足不同客户的不同需求,他的店有一点像‘万事屋’的性质。如此一来,只要一个动态代理类,就能完成所有的事
一.先看静态代理:一个代理类只能帮一个目标对象(被代理类)完成一件事
package com.ergou.spirngboot;
import org.junit.Test;
public class ProxyTest {
//1.声明接口(房屋出售)
interface HouseSale{
void SaleHouse();
}
//2.代理类和被代理类同时实现接口
//中介人 代理类(拿到房源)
class Agencyer implements HouseSale{
private Customer customer;
public Agencyer(Customer customer) {
this.customer = customer;
}
@Override
public void SaleHouse() {
customer.SaleHouse();
System.out.println("我是房产中介人,我能替你买房子!但要收费");
System.out.println("我替你买到房子了");
}
}
//消费者 被代理类 (想要买房子)
class Customer implements HouseSale{
@Override
public void SaleHouse() {
System.out.println("我是实际买房者,我想买房!");
}
}
@Test
public void test(){
//顾客发起需求--》中间人找到房源--》中间人替你完成买房
Customer customer=new Customer();
Agencyer a = new Agencyer(customer);
a.SaleHouse();
//我是实际买房者,我想买房!
//我是房产中介人,我能替你买房子!但要收费
//我替你买到房子了
}
}
核心代码
代理类
![]()
执行:给被代理类赋值
![]()
静态代理实现总结:
1.创建一个接口
2.创建代理类(注:一定要拥有被代理类这个属性)和被代理类两个类实现1创建的接口
3.执行:3.1创建被代理类的对象(目标对象)3.2通过有参构造器创建代理类的对象,参数为被代理类的3.3执行代理类的方法。
二.动态代理:一个代理类能帮不同的目标对象(被代理类)完成不同的事
/**
* @create by 程二狗 on 2018/10/16 0016
**/
public class ProxyTest1 {
//商店卖东西
interface Shop{
void sale();
}
//顾客买东西
class Customer implements Shop{
@Override
public void sale() {
System.out.println("我是陈二狗,我想在商店里买一台笔记本!");
}
}
//通用代理类:自定义一个类实现InvocationHandler接口,重写invoke()方法
class MyInvocationHandler implements InvocationHandler{
//理解:我是通用代理类,既然你想让我代替你完成事情,你就必须把你要做的事情告诉我,所以我必须
//要拥有被代理类(目标对象),即目标对象是我的一个属性。
//既然我想得到一个万能代理类,那么我的对象类型就必须是Object类型,如果还是Customer,那么就
//只能代理 Customer 类了。
private Object object;//被代理对象(目标对象)
// private Customer customer;//被代理对象(目标对象)
//下面代码的目的:1.通过构造方法给被代理对象赋值 2.返回一个万能代理对象
//理解:参1:加载器(加载代理对象类的加载器实际上就是加载被代理对象的加载器,二者类字节码的加
//载都是同一个加载器,参数2:实现的借口(代理类和被代理类都需要实现相同的接口)
//参3: InvocationHandler 就是MyInvocationHandler ,即本类this
public Object getProxyObject(Object object){
this.object=object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
}
//当通过代理类的对象对被重写方法的调用时,都会转化为对如下invoke方法的调用。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(object,args);
}
}
@Test
public void test(){
//1.被代理的对象(现在是顾客)
Customer customer = new Customer();
//1.1 被代理的对象,假设是学生
// Student s = new Student();
//2.创建一个实现InvocationHandler接口的类对象
MyInvocationHandler handler = new MyInvocationHandler();
//3.调用blind方法,动态的返回一个实现Shop接口的代理对象
Shop shopProxy = (Shop)handler.blind(customer);//传入学生对象即可
shopProxy.sale();//转到对invoke方法的调用
}
}
小tips:动态代理核心代理理解
1.我是通用代理类,既然你想让我代替你完成事情,你就必须把你要做的事情告诉我,所以我必须
要拥有被代理类(目标对象),即目标对象是我的一个属性。
既然我想得到一个万能代理类,那么我的属性的对象类型就必须是Object类型,如果还是Customer,那么就
只能代理 Customer 了。
2.下面代码的目的:1.通过构造方法给被代理对象赋值 2.调用Proxy类的静态方法newProxyInstance()创建一个万能代理对象。
参1:加载器(加载代理对象类的加载器实际上就是加载被代理对象的加载器,二者类字节码的加载都是同一个加载器
参2:实现的借口(代理类和被代理类都需要实现相同的接口)
参3:InvocationHandler 就是MyInvocationHandler ,即本类this
![]()
当通过代理类的对象调用被重写的方法时,都会转化为对如下invoke方法的调用。
个人理解:静态代理时,我们执行代理类的方法就是执行代理类重写了接口的方法;动态代理类也是要执行重写接口的方法,即invoke()方法;我们在静态代理中执行代理类重写接口方法的同时,在这个方法中还调用了被代理类的方法,所以动态代理也同理:执行了代理类的invoke()方法,在这个方法中还要去执行被代理类的方法,被代理类的方法即method.invoke(object,args),因为代理类和被代理类都是重写同一个方法,所以Method对象是同一个,参数也相同。利用反射去调一个方法,是类的运行时去进行的,这就是动态。。。
![]()
对比反射,我们用反射创建了对象,那么是如何调用反射的呢?(其中stu为对象)
![]()
如果你对java的反射机制还不大熟悉,请参考我的另一篇文章java的反射机制
动态代理总结:
1.创建一个接口
2.创建被代理类(目标)对象实现接口
3.创建一个万能代理类class MyInvocationHandler implements InvocationHandler{ private Object object; public Object blind(Object object){ this.object=object; return >Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(object,args); } }
4.传入不同被代理类,动态生成对应的代理类,执行代理类的方法
public void test(){ Customer customer = new Customer(); MyInvocationHandler handler = new MyInvocationHandler(); Shop shopProxy = (Shop)handler.blind(customer); shopProxy.sale(); }
三.动态代理的运用:spring框架日志记录==
业务场景:现在有一个user类,有2个方法,我需要在这2个方法执行前和执行后添加日志记录,如何实现?
3.1 创建接口(业务)
/**
* @create by 程二狗 on 2018/10/19 0019
**/
public interface User {
void add();
void update();
}
3.2创建被代理类实现接口(业务实现)
/**
* @create by 程二狗 on 2018/10/19 0019
**/
public class UserService implements User {
@Override
public void add() {
System.out.println("user添加");
}
@Override
public void update() {
System.out.println("user更新");
}
}
3.3动态创建代理类(代理目标对象去实现业务,并添加日志)
/**
* @create by 程二狗 on 2018/10/19 0019
**/
public class Myhandler implements InvocationHandler {
private Object object;
public Object getProxy(Object object){
this.object = object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是user方法执行前的日志记录<----");//额外增加的方法,和业务无关
Object obj = method.invoke(object,args);
System.out.println("我是user方法执行后的日志记录---->");//额外增加的方法,和业务无关
return obj;
}
}
3.4 测试
@Test
public void logTest(){
Myhandler handler = new Myhandler();
UserService target = new UserService();
User proxyUser = (User)handler.getProxy(target);
proxyUser.add();
System.out.println("=======================");
proxyUser.update();
// 我是user方法执行前的日志记录<----
// user添加
// 我是user方法执行后的日志记录---->
// =======================
// 我是user方法执行前的日志记录<----
// user更新
// 我是user方法执行后的日志记录---->
}
小结动态代理优势:日志记录和正常的业务(添加、更新)没有关系,实现了代码的解耦,而且让业务更灵活。比如商品举行打折活动之类的都可以通过动态代理去实现
网友评论