1、代理模式
(1)概念:
其中目标对象实现真正的功能,但是代理对象可以对目标对象的功能做进一步的扩充。
(2)设计模式:
设计模式代表了最佳的实践,通常被有经验的面向对象的软件开发者所采用的,它是开发中面临的一般问题的解决方案,这些解决方案是众多的软件开发人员经过相当长的实践的经验和错误总结出来的。
(3)举例:
如果设计一个类该类中含有加减乘除四个方法,现在需要给每一个方法添加测试方法执行时间的代码,如果不使用代理的话,就需要对每一个方法进行修改,需要修改多次。违背了开闭原则(OCP,对扩展开放,修改关闭)和单一职责(SRP)
2、静态代理
是在程序运行前就已经存在代理类的字节码文件,静态代理通常是对原有业务逻辑的扩充,通过让代理类持有真实对象,在原代码中调用代理类方法来添加我们需要的业务逻辑。例如:买车不去工厂而是去4S店。
(1)创建一个接口:
interface Animal {
public abstract void show();
}
(2)代理类:
public class Fish implements Animal {
Sheep sheep=new Sheep();
@Override
public void show() {
sheep.show();
System.out.println("我爱游泳!");
}
}
创建被代理类的对象,在代理类的方法中调用被代理类的方法,在这个过程中可以实现对被代理类的功能的扩充。
(3)被代理类:
public class Sheep implements Animal{
@Override
public void show() {
System.out.println("我爱吃青草");
}
}
(4)测试类:
public class Test {
public static void main(String [] args){
Fish fish=new Fish();
fish.show();
}
}
测试结果:
Sheep最爱吃青草,在他被fish类代理之后还学会了一项新的技能:游泳
(5)静态代理的缺点:
如果有多个类需要代理,那么就需要创建多个代理类分别代理目标对象,工作量较大,不利于维护。
3、动态代理(JDK代理,接口代理)
(1)好处:
动态代理是利用的反射机制动态地生成代理的对象,我们不需要知道谁代理谁。代理类的那部分代码被固定下来了,不会因为业务的增加而逐渐庞大。
可以实现AOP编程
解耦
(2)创建一个接口:
interface Animal {
public abstract void show();
}
(3)创建代理类:
实现动态代理需要将要扩展的功能写在InvocationHandler实现类里
使用newProxyInstance方法,该方法需要接收三个参数
代理对象不需要实现接口,但是目标对象一定要实现接口
public class Fish implements Animal {
@Override
public void show() {
Animal objectProxy= (Animal) Proxy.newProxyInstance(//创建接口实例
Animal.class.getClassLoader(),//与目标对象有相同的类加载器,动态代理类运行时创建,将类加载到内存
new Class[]{Animal.class},//被代理的类所实现的接口(可以是多个)
new InvocationHandler() {//绑定代理类的方法
@Override//提供invoke方法,代理类的每一个方法执行时,都将调用一次invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我在前!!");
method.invoke(new Sheep(),args);//执行目标对象的方法
System.out.println("我在后!!");
return null;
}//proxy:代理后的实例对象
//method:对象被调用的方法
//args:调用时的参数
}
);
objectProxy.show();
}
}
(4)被代理类:
public class Sheep implements Animal{
@Override
public void show() {
System.out.println("我爱吃青草");
}
}
(5)测试类:
public class Test {
public static void main(String [] args){
Fish fish=new Fish();
fish.show();
}
}
测试结果:
4、cglib代理(cglib字节码增强)
(1)概念:
需要导入jar包:核心包和依赖包(spring_core.jar已经集成了这两个包,因此,导入此包即可)
子类是在调用的时候才生成的
使用目标对象的子类的方式实现的代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展,能够在运行时动态生成字节码,可以解决目标对象没有实现接口的问题
缺点:被final或static修饰的类不能用cglib代理,因为它们不会被拦截,不会执行目标对象的额外业务方法