代理模式
1 代理的概念
代理的作用:为了实现在不更改被代理类的基础上,对被代理类的功能进行扩展。
代理对象:对被代理对象的功能进行扩展(中介)
目标对象:被代理对象。
原则:代理对象,代理的是目标对象,不能有更多的功能。
2 实现方式
2.1 静态代理
2.1.1 静态代理的要求
- 代理类和被代理类必须实现相同的接口。
- 代理类中存在被代理类的对象的引用。
2.1.2 代码实现
package com.atguigu.proxytest;
/**
* 静态代理举例
* 特点:代理类和被代理类在编译期间就已经确定了。
*
* @author 龍
*/
interface ClothFactory {
/**
* 生产衣服的方法
*/
void produceCloth();
}
/**
* 代理类
*/
class ProxyClothFactory implements ClothFactory {
/**
* 使用被代理类对象进行实例化
*/
private ClothFactory factory;
public ProxyClothFactory(ClothFactory factory) {
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂进行一些准备工作");
factory.produceCloth();
System.out.println("代理工厂进行一些后续的收尾工作");
}
}
/**
* 被代理类
*/
class NikeClothFactory implements ClothFactory {
@Override
public void produceCloth() {
System.out.println("Nike生产了一批运动服装");
}
}
/**
* @author 龍
*/
public class StaticProxyTest {
public static void main(String[] args) {
NikeClothFactory nike = new NikeClothFactory();
ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nike);
proxyClothFactory.produceCloth();
}
}
2.1.3 存在的问题
- 代理类和被代理类必须实现相同的接口。
- 代理类和被代理类在编译时期,就已经确定。
- 只可以扩展接口中的方法。
- 一旦接口增加方法,就需要对目标对象和代理类进行功能扩展。
2.2 动态代理
2.2.1 要求
- 必须实现一个接口
- 代理类存在一个
2.2.2 代码实现
package com.atguigu.proxytest;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author 龍
*/
interface Human {
/**
* 能力
*
* @return :能力
*/
String getBelief();
/**
* 吃食物
*
* @param food :食物
*/
void eat(String food);
}
/**
* 超人类
*/
class SuperMan implements Human {
@Override
public String getBelief() {
return "I can Fly";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃" + food);
}
}
/**
* 根据被代理类创建代理类对象
*/
class ProxyFactory {
public static Object getProxyInstance(Object obj) {
//调用此方法,返回一个代理类对象
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
Object o = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
return o;
}
}
class MyInvocationHandler implements InvocationHandler {
//被代理类对象
private Object object;
public void bind(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//当我们通过代理类对象调用方法A的时候就会调用该方法,将被代理类要求执行的方法a的功能就生命在invoke()中
HumanUtil util = new HumanUtil();
util.method1();
//类似于AOP:面向切面编程。
Object invoke = method.invoke(object, args);
util.method2();
return invoke;
}
}
class HumanUtil {
public void method1() {
System.out.println("通用方法1");
}
public void method2() {
System.out.println("通用方法2");
}
}
/**
* 存在的问题:
* 一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
* 二:当通过代理类的对象调用方法时,如何动态的去调用被代理的同名方法
*
* @author 龍
*/
public class ProxyTest {
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
//此时为代理类对象
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
//会自动的调用被代理类中同名的方法。
proxyInstance.eat("四川麻辣烫");
String belief = proxyInstance.getBelief();
System.out.println(belief);
NikeClothFactory nikeClothFactory = new NikeClothFactory();
ClothFactory proxyInstance1 = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);
proxyInstance1.produceCloth();
}
}
2.2.3 动态代理
优点:
- 不需要我们手动的创建代理类,只需要编写一个动态处理器,真正的代理对象由JDK在运行的时候为我们动态的创建。
- 减少了对业务接口的依赖,降低了耦合度。
缺点:
- 无法摆脱对接口的依赖,必须要实现一个接口,这是由java的继承机制注定了这些被动态代理类必须实现一个接口。
2.3 cglib
2.3.1 出现背景
因为JDK要求动态代理必须实现通过接口定义业务方法,对于没有接口的类,如何实现动态代理,这就是CGlib要实现的。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。Cglib又被称为:子类代理。
2.3.2 代码实现
package com.atguigu.proxytest;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLibTest {
/*cglib代理:子类代理
* 特点创建目标类的子类 通过重写父类方法来实现目标类功能的控制
* */
public static void main(String[] args) {
Teacher t=new Teacher(31, "韩寒");//定义目标类对象
ZiProxyFactroy factroy=new ZiProxyFactroy(t);//创建工厂类对象并关联目标类对象
//调用工厂类对象的getInstance方法动态获取目标类的子类对象
Teacher proxy=(Teacher)factroy.getInstance();
proxy.hehe();
proxy.teach();
}
}
//1 创建子类对象工厂类 实现MethodInterceptor
class ZiProxyFactroy implements MethodInterceptor{
//2 定义成员变量记录目的对象
private Object target;
public ZiProxyFactroy(Object target) {//通过构造方法关联目标对象
this.target = target;
}
//3 目标对象的方法被调用时 intercept方法就会执行
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println(method.getName()+"+++++方法被调用前的域处理代码");
Object result=method.invoke(target, args);
System.out.println(method.getName()+"-----方法被调用后的后处理代码");
return result;
}
//4 定义一个动态生成目标类的子类对象
public Object getInstance() {
Enhancer er=new Enhancer(); //4.1 创建加强工具类
er.setSuperclass(target.getClass()); //4.2 指定要加强的父类(目标类)
er.setCallback(this); //4.3 设置回调函数
return er.create(); //4.4 返回一个子类对象
}
}
//5 定义目标类
class Teacher{
int age; String name;
public Teacher(int age, String name) {
this.age = age;
this.name = name;
}
public Teacher() {
super();
}
void hehe() {
System.out.println("老师::"+age+","+name);
}
void teach() {
System.out.println(name+"正在教书!!!");
}
}
注:需要导入jar包 spring-core-4.3.18.RELEASE.jar