其实代理模式顾名思义就是使用一个代理类来代替原对象,来进行一些操作。
譬如刚毕业的小菜,去北京,刚去自己找房子租很困难,要不价格太贵,要不就是很便宜环境不太好,总是没顺心的,便会给中介打电话,这样中介就会帮小菜去找房子,因为中介掌握房源的信息很多很全面,这样找房子的活就由中介代理小菜去找了。这就是一个代理的过程。
静态代理、动态代理、cglib代理。
关键: 代理对象,要实现与目标对象一样的接口
实现:
小菜学生类:
public class XiaoCai implements IHouseFunction{
@Override
public void getApartmentAbility() {
// TODO Auto-generated method stub
System.out.println("------得到房子------");
}
}
搞到房子的技能接口:
//租房子接口
public interface IHouseFunction {
//租到房子的技能
public void getApartmentAbility();
}
房东类(代理类):
//房东类同样也可以叫做代理类
public class Landlord implements IHouseFunction{
private IHouseFunction houseFunction;
//通过构造器传入目标对象
public Landlord(IHouseFunction houseFunction) {
this.houseFunction = houseFunction;
}
public void setHouseFunction(IHouseFunction houseFunction) {
this.houseFunction = houseFunction;
}
@Override
public void getApartmentAbility() {
// TODO Auto-generated method stub
System.out.println("房东开始给小菜找房子了。。。。");
houseFunction.getApartmentAbility();
System.out.println("房东已经帮小菜找到房子了。。。。");
}
}
测试类:
public class Test {
public static void main(String[] args) {
IHouseFunction houseFunction =new XiaoCai();
Landlord landlord =new Landlord(houseFunction);
//从调用房东技能可以看出,房子是代理搞到的
landlord.getApartmentAbility();
}
}
结果:
总结:
静态代理的优点:可以做到不修改目标对象功能的前提下,对目标对象实现了扩展,遵循了开闭原则。
静态代理的缺点:由于静态代理其本身的特点,代理类和目标对象实现同一个接口,同时这也是一个缺点,如果目标对象需要增加更多,那么需要增加更多的代理类。同时接口也在增加更多,都需要维护,这样很麻烦。所以可以利用之前博文中的工厂模式,增加对象,哈哈。而这种策略就被叫做动态代理(或者叫JDK代理)。
关键:代理类不用实现接口,而代理类对象是通过JDK生成的,动态的在内存中构建代理对象(想想也知道这东西肯定不会凭空产生),所以同时需要传入目标对象,以及实现的接口,剩下的jdk帮我们去做了。哈哈
实现:
小菜学生类:
public class XiaoCai implements IHouseFunction{
@Override
public void getApartmentAbility() {
// TODO Auto-generated method stub
System.out.println("------得到房子------");
}
}
搞到房子的技能接口:
//租房子接口
public interface IHouseFunction {
//租到房子的技能
public void getApartmentAbility();
}
房东类(代理类):
//房东类同样也可以叫做代理类
public class Landlord {
//定义目标对象
private Object target;
//还是通过构造器传入
public Landlord(Object target) {
super();
this.target = target;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] arg2)
throws Throwable {
System.out.println("房东开始给小菜找房子了。。。。");
Object retValue =method.invoke(target, arg2);
System.out.println("房东已经帮小菜找到房子了。。。。");
return retValue;
}
});
}
}
测试类:
public class Test {
public static void main(String[] args) {
IHouseFunction target =new XiaoCai();
IHouseFunction houseFunction =(IHouseFunction) new Landlord(target).getProxyInstance();
houseFunction.getApartmentAbility();
System.out.println("目标对象:"+target.getClass());
System.out.println("代理对象:"+houseFunction.getClass());
}
}
结果:
总结:
动态代理的优点:代理对象不需要实现接口。
动态代理的缺点:目标对象却仍然需要实现接口。如果我需要一个目标对象扩展功能,但是却没有实现目标接口,动态代理又玩不转了。我们可以使用子类实现对目标对象的扩展,这种方式叫cglib代理(或者叫做子类代理)。
关键:cglib是在运行期扩展java类与实现java接口。cglib包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
实现:
小菜学生类:
public class XiaoCai {
public void getApartmentAbility() {
// TODO Auto-generated method stub
System.out.println("------得到房子------");
}
}
房东类(代理类):
//房东类同样也可以叫做代理类
public class Landlord implements MethodInterceptor{
//维护一个目标对象
private Object target;
public Landlord(Object target) {
this.target =target;
}
//给目标对象创建代理对象
public Object getProxyInstance(){
Enhancer en =new Enhancer();
en.setSuperclass(target.getClass());
en.setCallback(this);
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] arg2,
MethodProxy proxy) throws Throwable {
System.out.println("房东开始给小菜找房子了。。。。");
Object retValue =method.invoke(target, arg2);
System.out.println("房东已经帮小菜找到房子了。。。。");
return retValue;
}
}
测试类:
public class Test {
public static void main(String[] args) {
XiaoCai xiaoCaiTarget =new XiaoCai();
XiaoCai xiaoCaiProxy =(XiaoCai) new Landlord(xiaoCaiTarget).getProxyInstance();
xiaoCaiProxy.getApartmentAbility();
System.out.println(xiaoCaiTarget.getClass());
System.out.println(xiaoCaiProxy.getClass());
}
}
结果:
总结:
需要注意的是:cglib代理:需要引入 cglib – jar文件。但是spring的核心jar包已经包含了cglib功能。所以项目要引入spring的核心jar包,否则不可以使用cglib代理。引入jar包之后,就可以方便的在内存中动态的构建子类实现代理了。