静态代理
了解了代理模式,直接看代码:
/**
* @Author: Forward Seen
* @CreateTime: 2022/03/31 15:10
* @Description:
*/
public interface TargetService {
/**
* 接口中默认的方法,该案例目的是要增强该方法的功能
*/
void service();
}
/**
* @Author: Forward Seen
* @CreateTime: 2022/03/31 15:10
* @Description: 目标对象
* 代理的目的是增强该类的对象的功能,我们称作该类的对象叫目标对象
*/
public class Target implements TargetService{
@Override
public void service() {
System.out.println("The program is running!");
}
}
/**
* @Author: Forward Seen
* @CreateTime: 2022/03/31 15:20
* @Description: 这里的代理对象TargetProxy目的是用于增强Target对象的功能,可以理解为给
* Target的方法添加代码
*/
public class TargetProxy implements TargetService{
private TargetService target;
public TargetProxy(TargetService target){
this.target = target;
}
/**
* 增强后的方法
* 在原方法前增加代码称作前置增强
* 在原方法后增加代码称作后置增强
* 很明显,代理对象的方法,其实就是在目标对象上做一些扩展
*/
@Override
public void service() {
System.out.println("前置增强。。。");
target.service();
System.out.println("后置增强。。。");
}
}
public class Test {
public static void main(String[] args) {
//正常使用目标对象的方法
Target target = new Target();
target.service();
System.out.println("------------------------------");
//使用代理对象
TargetProxy targetProxy = new TargetProxy(target);
targetProxy.service();
}
}
代理类实现了目标类的方法的扩展,像这样,代理模式中的所有角色(代理对象、目标对象、目标对象的接口)在编译期就确定好了的,就是静态代理,而动态代理是在程序运行时增强代码的功能。
静态代理可以避免创建一个大对象,使用一个小对象就能代替真实的大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。
动态代理
前面介绍了静态代理,虽然静态代理模式很好用,但是静态代理还是存在一些局限性的, 比如使用静态代理模式需要程序员手写很多代码,这个过程是比较浪费时间和精力的。一旦 需要代理的类中方法比较多,或者需要同时代理多个对象的时候,这无疑会增加很大的复杂度。
动态代理中的代理类并不要求在编译期就确定,而是可以在运行期动态生成,从而实现对目标对象的代理功能。
反射是动态代理的一种实现方式。
动态代理主要有两种实现方式:
- jdk代理:基于接口的动态代理技术
目标对象的方法需要被增强,这个目标对象必须有接口,在运行期间要基于这个接口动态地生成代理对象,而这个代理对象是基于接口的,目标接口有什么方法,目标对象也就有什么方法,而动态代理生成的对象也有对应的方法,这样就保证代理对象跟目标对象有相同的方法。 - cglib代理:基于父类的动态代理技术
cglib代理没有了接口,cglib技术是为目标对象动态地生成代理对象或者说生成子对象,子对象的有目标对象的全部方法,且子对象的功能更加强大,注意这不是继承,而是代理对象是基于目标对象的,它是在程序运行时动态生成的。调用的时候调用的是代理对象,而代理对象内部是调用目标对象,只不过在调用的时候有其他代码的介入,进而增强目标对象。
使用JDK实现动态代理
public interface TargetService {
/**
* 接口中默认的方法,该案例目的是要增强该方法的功能
*/
void service();
}
/**
* @Author: Forward Seen
* @CreateTime: 2022/03/31 15:10
* @Description: 目标对象
* 代理的目的是增强该类的对象的功能,我们称作该类的对象叫目标对象
*/
public class Target implements TargetService {
@Override
public void service() {
System.out.println("The program is running!");
}
}
public class TargetProxy {
public static Object getInstance(TargetService target){
//增强对象
Advice advice = new Advice();
/**
* @param 1.目标对象的类加载器
* @param 2.目标对象相同的接口字节码对象数组
* @param
* @return 动态生成的代理对象,用TargetService父接口接收
*/
TargetService proxyTarget = (TargetService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
/**
* 调用代理对象的任何方法 实质执行的都是invoke方法
* @param proxy 代理对象
* @param method 代理的方法
* @param args 方法的参数
* @return 方法的返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.before(); //前置增强
Object invoke = method.invoke(target, args); //执行目标方法
advice.after(); //后置增强
return invoke;
}
}
);
return proxyTarget;
}
}
public static void main(String[] args) {
//目标对象
Target target = new Target();
//创建代理对象
TargetService proxyTarget = (TargetService) TargetProxy.getInstance(target);
//调用代理对象的增强方法
proxyTarget.service();
}
使用cglib实现动态代理
与jdk方式不一样的是,cglib不需要接口了,只要目标对象,代理对象就类似于目标对象的子类。
cglib属于第三方框架,我们的Spring框架底层用的就是cglib,所以我们可以导入Spring的核心jar包来作为实现环境。
这次目标对象不需要接口了哦
/**
* @Author: Forward Seen
* @CreateTime: 2022/03/31 15:10
* @Description: 目标对象
*/
public class Target {
public void service() {
System.out.println("The program is running!");
}
}
代理对象的实现几乎与上面一致
public class TargetProxy {
public static Target getInstance(Target target){
//1.创建增强器
Enhancer enhancer = new Enhancer();
//2.设置父类(目标)
enhancer.setSuperclass(Target.class);
//3.设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("前置增强。。");
Object invoke = method.invoke(target, objects);
System.out.println("后置增强。。");
return invoke;
}
});
//4.创建代理对象
return (Target)enhancer.create();
}
}
使用代理对象
public class Test {
@org.junit.Test
public void testCglib(){
Target target = TargetProxy.getInstance(new Target());
target.service();
}
}