什么是代理
代理本身是一种设计模式
例:银行转账的系统的三个功能
1.判断用户的身份,做用户验证,判断用户金额
2.转账的方法
3.事后服务
如果在一个方法中写入这三件事
这会使方法的功能量太大
如何降低功能量?
1.将这一个方法转换成三个方法
这会使功能比较灵活,效率比较高,但是没有考虑扩容的问题
2.支付宝代理转账业务
如果本身是一个银行,需要向支付宝公司提供转账方法
我们可以把验证和事后服务这两个业务交给支付宝公司,银行只需要控制转账方法。
代理模式
代理模式:最核心的业务也就是转账的业务自己做,由支付宝公司代理,用户不能直接进行转账服务这种最核心业务,需要通过支付宝进行转账代理
支付宝公司对银行的转账业务进行代理,用户只能去访问支付宝,再由支付宝进行身份核验之后,去调用当前的转账方法。
代理模式的好处
1.防止用户直接访问核心方法,带来一些不必要的危机
用户直接访问转账服务,就可能造成金融上的问题
2.能够对核心方法进行功能的增强
java代理怎么用?
java代理
1.静态代理
也称为 基于JDK实现的静态代理
静态代理的模式
核心类(目标类)生成核心对象(目标对象),同时由代理类实现代理对象,再由代理对象代理核心对象
核心类和代理类都会实现接口
接口起到的作用就是通知当前代理类所要代理的核心类的核心功能
静态代理流程图
例:支付宝代理银行转账的静态代理
银行类----->核心类
package work0903;
public class YinHang implements ZhanZhang{
@Override
public void zhuanzhang(String A, String B, Double money) {
System.out.println(A+"给"+B+"转账了"+money);
}
}
支付宝类------>代理类
package work0903;
public class ZhiFuBao implements ZhanZhang{
//定义被代理的类---------->核心类
private YinHang yinHang=new YinHang();
private void yanzheng(String A, String B, Double money){
System.out.println("对A进行了身份验证");
System.out.println("对B进行了身份验证");
System.out.println("对转账金额进行了验证");
}
@Override
public void zhuanzhang(String A, String B, Double money) {
yanzheng(A,B,money);
yinHang.zhuanzhang(A,B,money);
fuwu();//功能增强
}
private void fuwu(){
System.out.println("转账完成后进行服务");
}
}
接口
package work0903;
public interface ZhanZhang {
//定义核心方法
public void zhuanzhang(String A,String B,Double money);
}
测试类
package work0903;
public class Test {
public static void main(String[] args) {
ZhiFuBao zhiFuBao=new ZhiFuBao();
zhiFuBao.zhuanzhang("张三","李四",100.0);
}
}
执行结果
执行流程
1.首先Test类的main方法入栈
2.创建zhifubao对象(代理对象)
3.zhifubao对象会创建yinhang对象(核心对象)
3.zhifubao对象中有yanzhen方法和fuwu方法,以及zhuanzhang方法
4.yinhang对象中也有自身的zhuanzhang方法(核心方法)
5.调用zhifubao中的zhuanzhang方法,该方法入栈
6.zhifubao中的zhuanzhang方法会继续调用yinhang的zhuangzhang方法
7.同时也会调用自身的yanzheng方法和fuwu方法,进行了业务增强
程序执行内存图
代理类和核心类的关系:
代理对象代理核心对象,核心对象在代理对象的内部
对于用户来说:用户调用代理对象,代理对象再调用核心对象,这样就防止了用户直接访问到当前核心对象所带来一些麻烦,同时的话还能对核心方法进行一系列的增强
示例:销售店代理衣服工厂
接口
package DaiLi;
public interface Clothes {
public void BuyClothes(String size);
}
核心类
package DaiLi;
public class ClothesFactory implements Clothes {
@Override
public void BuyClothes(String size) {
System.out.println("定制一件大小为"+size+"的衣服");
}
}
代理类
package DaiLi;
public class XSD implements Clothes{
//1.代理目标类
private ClothesFactory clothesFactory=new ClothesFactory();
private void fuwu(){
System.out.println("销售店的售后服务");
}
@Override
public void BuyClothes(String size) {
clothesFactory.BuyClothes(size);
fuwu();
}
}
测试类
package DaiLi;
public class Test {
public static void main(String[] args) {
XSD xsd=new XSD();
xsd.BuyClothes("XXL");
}
}
执行结果
静态代理的缺陷:
用一个代理类代理多个目标类是很难实现的,会出现问题
例:销售店不仅代理衣服工厂,还代理鞋子工厂,
鞋子接口
package DaiLi;
public interface Shoes {
public void BuyShoes(String size);
}
核心类
package DaiLi;
public class ShoeFactory implements Shoes{
@Override
public void BuyShoes(String size) {
System.out.println("定制一款大小为"+size+"的鞋子");
}
}
代理类
package DaiLi;
public class XSD implements Clothes,Shoes{
//1.代理目标类
private ClothesFactory clothesFactory=new ClothesFactory();
private ShoeFactory shoeFactory=new ShoeFactory();
private void fuwu(){
System.out.println("销售店的售后服务");
}
@Override
public void BuyClothes(String size) {
clothesFactory.BuyClothes(size);
fuwu();
}
@Override
public void BuyShoes(String size) {
shoeFactory.BuyShoes(size);
fuwu();
}
}
测试类
package DaiLi;
public class Test {
public static void main(String[] args) {
XSD xsd=new XSD();
xsd.BuyClothes("XXL");
xsd.BuyShoes("39");
}
}
静态代理的模式图
每一个代理对象当中代理的目标类太多了,主要是因为在每个代理对象当中都会创建全部的目标对象。
2.动态代理
动态代理的分类
1.基于JDK实现的动态代理
2.基于CGLB实现的动态代理
动态代理定义:
所谓动态代理,就是当前的代理类去动态的生成代理对象,匹配每个目标对象。
代理类实现代理对象,一个类可以实现多个对象,每个代理对象代理一个目标对象,只包含自己要代理的目标对象
动态代理模式图
代理类会生成代理对象,专门代理目标类
动态代理的实现
1.动态代理一对一模式的形成
代理类会指定自己要代理的目标类对象
package DaiLi;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DTXSD {
private Object object; //目标类
public DTXSD(Object o) {
object = o;
}
}
package DaiLi;
public class Test {
public static void main(String[] args) {
//实现一个动态代理对象代理一个目标对象的方法
//方法1
// DTXSD dtxsd1=new DTXSD(new ClothesFactory());
// 传入该动态代理对象要代理的目标对象
ClothesFactory clothesFactory=new ClothesFactory();
DTXSD dtxsd1=new DTXSD(clothesFactory);
ShoeFactory shoeFactory=new ShoeFactory();
DTXSD dtxsd2=new DTXSD(shoeFactory);
}
}
内存图
在动态代理当中,我们不需要特意创建对象,反射会使创建对象的方式有很多种,不需要额外创建对象。
package DaiLi;
public class Test {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
//实现一个动态代理对象代理一个目标对象的方法
//方法1
// DTXSD dtxsd1=new DTXSD(new ClothesFactory());
// 新建目标对象,传入该动态代理对象要代理的目标对象
// ClothesFactory clothesFactory=new ClothesFactory();
// DTXSD dtxsd1=new DTXSD(clothesFactory);
// ShoeFactory shoeFactory=new ShoeFactory();
// DTXSD dtxsd2=new DTXSD(shoeFactory);
//方法2
DTXSD dtxsd1=new DTXSD(ShoeFactory.class);//获取类对象,再创建对象
}
}
package DaiLi;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DTXSD {
private Object object; //目标类
public DTXSD(Class o) throws InstantiationException, IllegalAccessException {
object=o.newInstance();//创建对象
}
}
2.如何完成相关的调用工作,实现相关的接口
a.代理类当中实现该方法知道目标类当中的核心方法是什么
//动态代理实现相关接口
//调用该方法知道目标类当中的核心方法是什么
public Object getProxyInstance(){
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
//object.getClass()获取目标类的类对象.getInterfaces()获取当前目标类的接口
//object.getClass()获取目标类的类对象.getClassLoader()获取当前目标类的构造器
//this代表当前对象,即代理对象
}
b.测试类调用该方法,知道核心方法是什么
ClothesFactory clothesFactory=new ClothesFactory();
//调用方法。获取目标类接口,知道核心方法
//1.
// DTXSD dtxsd1=new DTXSD(clothesFactory);
// dtxsd1.getProxyInstance();
//2.
DTXSD dtxsd1= (DTXSD) new DTXSD(clothesFactory).getProxyInstance();//强制类型转化
c.对核心方法进行调用
代理类实现 InvocationHandler接口,通过重写invoke方法对核心方法进行调用。
用接口接收获悉的核心方法
为什么用接口?
调用核心方法的方式有两种:
1.目标类对象直接调用,这会使用户可以直接访问核心方法,会造成一定的影响
2.通过接口调用
实现动态代理代码
package DaiLi;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DTXSD implements InvocationHandler {
private Object object; //目标类
public DTXSD(Object o){
object=o;
}
//动态代理实现相关接口
//调用该方法知道目标类当中的核心方法是什么
public Object getProxyInstance(){
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
//object.getClass()获取目标类的类对象.getInterfaces()获取当前目标类的接口
//object.getClass()获取目标类的类对象.getClassLoader()获取当前目标类的构造器
//this代表当前对象,即代理对象
}
//
//通过invoke方法对核心方法进行调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(object,args);
return null;
//三个参数的讲解
//1.Object:jdk创建的代理类,无需赋值
//2.Method:目标类当中的方法,jdk提供,无需赋值
//3.Object[]:目标类当中的方法的参数,jdk提供,无需赋值
}
}
package DaiLi;
public class Test {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
//实现一个动态代理对象代理一个目标对象的方法
//方法1
// DTXSD dtxsd1=new DTXSD(new ClothesFactory());
// 新建目标对象,传入该动态代理对象要代理的目标对象
ClothesFactory clothesFactory=new ClothesFactory();
DTXSD dtxsd1=new DTXSD(clothesFactory);
Clothes clothes= (Clothes) dtxsd1.getProxyInstance();//用接口接收核心方法
clothes.BuyClothes("XL");
ShoeFactory shoeFactory=new ShoeFactory();
DTXSD dtxsd2=new DTXSD(shoeFactory);
Shoes shoes= (Shoes) dtxsd2.getProxyInstance();
shoes.BuyShoes("39");
}
}
运行结果
完整代码
测试类
package DaiLi;
public class Test {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
//实现一个动态代理对象代理一个目标对象的方法
//方法1
// DTXSD dtxsd1=new DTXSD(new ClothesFactory());
// 新建目标对象,传入该动态代理对象要代理的目标对象
ClothesFactory clothesFactory=new ClothesFactory();
DTXSD dtxsd1=new DTXSD(clothesFactory);
Clothes clothes= (Clothes) dtxsd1.getProxyInstance();//用接口接收核心方法
clothes.BuyClothes("XL");
ShoeFactory shoeFactory=new ShoeFactory();
DTXSD dtxsd2=new DTXSD(shoeFactory);
Shoes shoes= (Shoes) dtxsd2.getProxyInstance();
shoes.BuyShoes("39");
}
}
动态代理类
package DaiLi;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DTXSD implements InvocationHandler {
private Object object; //目标类
public DTXSD(Object o){
object=o;
}
//动态代理实现相关接口
//调用该方法知道目标类当中的核心方法是什么
public Object getProxyInstance(){
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
//object.getClass()获取目标类的类对象.getInterfaces()获取当前目标类的接口
//object.getClass()获取目标类的类对象.getClassLoader()获取当前目标类的构造器
//this代表当前对象,即代理对象
}
//
//通过invoke方法对核心方法进行调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(object,args);
fuwu();
return null;
//三个参数的讲解
//1.Object:jdk创建的代理类,无需赋值
//2.Method:目标类当中的方法,jdk提供,无需赋值
//3.Object[]:目标类当中的方法的参数,jdk提供,无需赋值
}
private void fuwu(){
System.out.println("销售店的售后服务");
}
}
代码执行流程
1. 初始化阶段
首先,Test类的main方法被调用,这是程序的入口点。
2. 创建动态代理对象
ClothesFactory clothesFactory = new ClothesFactory();:创建了一个ClothesFactory对象,这个对象实现了Clothes接口,用于定制衣服。
DTXSD dtxsd1 = new DTXSD(clothesFactory);:创建了一个DTXSD对象,这是动态代理的实现类。DTXSD实现了InvocationHandler接口,并且在构造函数中接收一个Object参数,这个参数实际上是目标类的实例(这里是ClothesFactory对象)。
3. 创建代理对象
Clothes clothes = (Clothes) dtxsd1.getProxyInstance();:通过getProxyInstance()方法创建了一个代理对象,这个方法使用了Proxy.newProxyInstance()。这个方法接收三个参数:
object.getClass().getClassLoader():类加载器,用于创建代理类。
object.getClass().getInterfaces():目标类实现的接口列表,这里是Clothes接口。
this:当前的DTXSD对象,作为InvocationHandler。
用接口接收目标类的核心方法
4. 调用代理对象的方法
clothes.ByClothes("XL");:调用代理对象的ByClothes方法,参数是"XL"。调用接口中的方法,由于接口中的方法只有定义,因此会调用目标类当中的方法,从而实现代理。实际上,这个调用会通过代理对象调用DTXSD对象的invoke方法。
5. invoke方法的执行
在invoke方法中:
method.invoke(object, args):调用目标类(ClothesFactory)的ByClothes方法,传入参数"XL"。
fuwu();:执行代理类内部的fuwu方法,打印一条服务消息。
较为浅显易懂的解释
1.首先main方法入栈
2.创建一个目标类对象clothesFactory
3.clothesFactory对象当中有一个Buyclothes方法
4.该对象实现了Clothes接口,接口中有对Buyclothes方法的定义
5.创建一个动态代理对象dtxsd1
6.该对象中有一个object类型的变量,变量指向clothesFactory对象的地址
7.动态代理对象中有getProxyInstance() .invoke()并且实现InvocationHandler接口
8.调用动态代理对象的getProxyInstance()方法,获取目标类所定义的核心方法
9.接口调用Buyclothes方法,实际会调用clothesFactory中的Buyclothes方法,是一个方法重写的过程
10会执行invoke方法中的内容
欢迎大家点赞,收藏,评论加关注呦