简单来说,代理就是不改变原有对象的基础上,对原有功能进行增强。java的三种创建代理对象的方式有三种,分别是静态代理、基于jdk的动态代理和基于CGLIB的动态代理。下面主要来看一下静态代理和动态代理代码方面的实现方式(用于理解java的代理机制)。
静态代理:
如下图所示,代理类通过实现目标类的接口,来对目标类的方法进行代理(代理主要针对的是方法),之所以通过接口,而不直接去找目标类,是因为直接去找目标类一是代码会写“死”,不够灵活,二是当有多个目标类时,代理起来太过繁琐而且容易出现矛盾,而接口是一个行业标准,对外开放,代理类通过接口实现对目标类的代理更加灵活,接口下面可以有很多实现类。

下面以购买衣服为例,来解释一下静态代理,如下图所示,我们想要买衣服,但是我们找不到生产衣服的工厂或者无法进行直接购买,这时候就需要去找代理商,代理商不光有工厂可以卖衣服的功能,同时还有强化的一些其他功能,售后服务等。回到java代理机制,也就是代理对象包含目标对象,在实现了目标对象方法的同时,添加了一些其他功能进行了强化,实现代码如下:

一、定义一个目标类接口:
public interface BuyClothes {
//购买衣服的方法
void buy(String size);
}
二、目标类(卖衣服的工厂),实现买衣服的接口和他的方法:
public class ClothesFactory implements BuyClothes{
@Override
public void buy(String size) {
System.out.println("您得到了一件尺码是"+size+"的衣服");
}
}
三、定义代理类(代理商),实现购买衣服的接口,就相当于把目标类的事做了:
public class ProxyClothes implements BuyClothes{
//目标类对象
public ClothesFactory clothesFactory;
//定义有参构造方法,创建代理类的时候,给他把目标类放进去
public ProxyClothes(ClothesFactory clothesFactory) {
this.clothesFactory = clothesFactory;
}
@Override
public void buy(String size) {
//售前服务
frontService();
//通过目标类对象把目标类方法调起来
clothesFactory.buy(size);
//售后服务
endService();
}
public void frontService(){
System.out.println("欢迎购买衣服,我们为您测量尺码");
}
public void endService(){
System.out.println("欢迎下次购买!");
}
}
四、写一个测试类测试一下(结果如下图),一个静态代理的示例就写完了!
public class Test {
public static void main(String[] args) {
ClothesFactory clothesFactory=new ClothesFactory();
ProxyClothes proxyClothes=new ProxyClothes(clothesFactory);
//直接去原工厂购买衣服(不使用代理类)
clothesFactory.buy("xxl");
System.out.println("======================");
//通过代理商购买衣服(使用代理类)
proxyClothes.buy("xxl");
}
}
运行结果:
目标类
==================
代理类

动态代理
继续上面的场景,那么问题来了,如果好多工厂都要让他代理,该怎么办呢?难道要每次添加目标工厂都要去改代码吗,答案肯定不是,使用动态代理,写一个生成代理类的模板,根据需要动态的生成代理类就可以了,代码如下:
一、在上面场景的基础上,我们添加了卖鞋的接口;
public interface BuyShoes {
void buy(String size);
}
二、写一个卖鞋的目标类(卖鞋的工厂)
public class ShoesFactory implements BuyShoes{
@Override
public void buy(String size) {
System.out.println("您得到了一件尺码为"+size+"的鞋子");
}
}
三、以下代码就可以理解为一个生成代理类的模板类;
public class Company implements InvocationHandler {
//目标对象,不知道是什么,所以写Object类,就是多态,父类引用可以指向任何子类对象
private Object object;
public Object getObject() {
return object;
}
//需要代理什么类,就调用set方法放进来
public void setObject(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//售前服务
frontService();
//不知道调用什么对象的什么方法,就使用通用的方法
method.invoke(object,args);
//售后服务
endService();
return null;
}
public void frontService(){
System.out.println("欢迎购买衣服,我们为您测量尺码");
}
public void endService(){
System.out.println("欢迎下次购买!");
}
//获取代购人员,通过set方法拿到具体对象后,生成代理类
public Object getProxyInstance(){
Object obj=Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
return obj;
}
}
四、测试
public static void main(String[] args) {
//动态代理
ClothesFactory clothesFactory=new ClothesFactory();
ShoesFactory shoesFactory=new ShoesFactory();
Company company=new Company();
//代理衣服
//调用set方法把clothes这个对象放进去
company.setObject(clothesFactory);
//获取代理类,父类无法调用子类方法,做一个强制类型转换
BuyClothes object=(BuyClothes)company.getProxyInstance();
object.buy("xxl");
System.out.println("=================================");
//代理鞋子
company.setObject(shoesFactory);
BuyShoes object1=(BuyShoes) company.getProxyInstance();
object1.buy("42");
}
测试结果:
