代理就是为其他对象提供一个代理以控制对某个对象的访问。

代理模式的优点:
代理可以分为静态代理和动态代理
由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了
package com.service;
/**
* @author Una
* @date 2022/8/11 12:46
* @description:提供给实体类继承
*/
public interface Animals {
public void eat();
}
package com.beans;
import com.service.Animals;
/**
* @author Una
* @date 2022/8/11 12:46
* @description:Cat类实现eat方法
*/
public class Cat implements Animals {
@Override
public void eat() {
System.out.println("猫吃鱼!!!!");
}
}
代理类
import com.beans.Cat;
import com.service.Animals;
/**
* @author Una
* @date 2022/8/11 12:47
* @description:
*/
public class CatProxy implements Animals {
private Animals animal;
//相当于签约绑定
@Override
public void eat() {
animal=new Cat();
animal.eat();
}
}
测试类
package com.proxy;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* @author Una
* @date 2022/8/11 12:53
* @description:
*/
public class CatProxyTest {
@Test
public void testAnimal(){
CatProxy catProxy=new CatProxy();
catProxy.eat();
}
}
由上可知;当我们需要使用时;在测试中;我们实际上看不到cat的身影就能执行cat的方法。
在程序运行时,运用反射机制动态创建而成,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码
动态代理分两类:
基于接口的代理和基于继承的代理;两类实现的代表分别是:JDK代理与CGlib代理。
JDK动态代理主要涉及java.lang.reflect包下的Proxy类和InvocationHandler接口。
jdk代理的要求:
(a)动态代理类需要实现InvocationHandler接口
(b)被代理的类也需要实现相应的接口
缺陷:不能直接代理Java类
package com.jdkProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author Una
* @date 2022/8/11 13:18
* @description:
*/
public class CatProxy2 implements InvocationHandler {
private Object target;//被代理的类对象
//绑定
public Object bind(Object target){
this.target=target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
//执行代理之前的业务逻辑
System.out.println("------调用核心业务前的代码--------");
//调用真正的业务方法,核心业务的执行结果在result中
result = method.invoke(target,args);
//执行代理之后的业务逻辑
System.out.println("------调用核心业务后的代码--------");
return result;
}
}
结果:

CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,为一个类创建子类,并在子类中采用方法拦截的技术拦截所有对父类方法的调用,并顺势加入横切逻辑。CGlib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理,因为采用的是继承,所以不能对final修饰的类进行代理。CGlib和JDK的原理类似,也是通过方法去反射调用目标对象的方法。
(a)代理类需要实现MethodInterceptor接口,重写该接口的interceptor()方法
(b)优点:可以直接代理类
package com.cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author Una
* @date 2022/8/11 13:36
* @description:
*/
public class CatProxy3 implements MethodInterceptor {
private Object target;
public Object bind(Object target){
//给业务对象赋值
this.target = target;
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦截
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("之前");
Object result = null;
try{
result = methodProxy.invokeSuper(o, objects);
}catch (Exception e){
System.out.println("得到:"+e.getMessage());
throw e;
}finally {
System.out.println("之后");
}
return result;
}
}
测试:
package com.cglib;
import com.beans.Cat;
import com.service.Animals;
import com.stillProxy.CatProxy;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* @author Una
* @date 2022/8/11 14:01
* @description:
*/
public class CatProxy3Test {
@Test
public void test(){
CatProxy3 catProxy3=new CatProxy3();
Cat cat=new Cat();
Animals animals=(Animals) catProxy3.bind(cat);
animals.eat();
}
}
结果
