静态代理
概念:静态代理就是指我们在给一个类扩展功能的时候,我们需要去书写一个静态的类,相当于在之前的类上套了一层,这样我们就可以在不改变之前的类的前提下去对原有功能进行扩展。
实现方式:静态代理通过一个代理类与被代理对象使用同一个接口(保证方法名相同),然后在代理类里通过组合的相识,吧需要被代理的对象传入,重写的对象中调用被代理对象的方法即可实现。
缺点:若有大量的类需要被代理,则会增大代码量。
实例:
共同接口
public interface PublicInterface {
/**
* 公共方法
*/
void publicMethod();
}
目标类
public class Target implements PublicInterface{
public String name;
public Target(String name) {
this.name = name;
}
@Override
public void publicMethod() {
System.out.println("我是:"+name);
}
}
代理类
public class ProxyClass implements PublicInterface{
public Target target;
public ProxyClass(Target target) {
this.target = target;
}
@Override
public void publicMethod() {
System.out.println("方法增强前");
target.publicMethod();
System.out.println("方法增强后");
}
}
测试
public class MyTest {
public static void main(String[] args) {
//正常调用
System.out.println("========正常调用==========");
Target target = new Target("目标");
target.publicMethod();
System.out.println("========代理调用==========");
ProxyClass proxyClass = new ProxyClass(target);
proxyClass.publicMethod();
}
}
执行结果
========正常调用==========
我是:目标
========代理调用==========
方法增强前
我是:目标
方法增强后
动态代理
动态代理简单来说就是在程序执行过程中,创建代理对象,通过代理对象执行方法,给目标类的方法增加额外的功能,也叫做功能增强。
Jdk动态代理
JDK动态代理主要由JDK提供的Proxy实现。动态代理类是在运行时生成指定接口的代理类,每个代理实例都有一个关联的调用处理程序对象,此对象实现InvocationHandler。
最终的业务逻辑是在InvocationHandler的invoke方法中实现。
JDK动态代理时基于接口的方式,换句话说就是代理类和目标类都实现同一接口,这样方法名就相同了。
实例
创建一个接口
public interface TargetService {
/**
* 第一个方法
*/
void one();
}
实现接口
public class TargetServiceImpl implements TargetService{
@Override
public void one() {
System.out.println("执行 one 方法");
}
}
创建代理类实现InvocationHandler类
public class MyInvocationHandler implements InvocationHandler {
public Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行代理类中的invoke方法");
System.out.println("调用方法的名称:"+method.getName());
Object result = null;
System.out.println("方法增强前");
result = method.invoke(target,args);
System.out.println("方法增强后");
return result;
}
}
调用
public class MyTest {
public static void main(String[] args) {
//创建目标对象
TargetService target = new TargetServiceImpl();
//创建InvocationHandler对象
MyInvocationHandler handler = new MyInvocationHandler(target);
//使用Proxy创建代理
TargetService proxy = (TargetService)Proxy.newProxyInstance(
//定义代理类的加载器
target.getClass().getClassLoader(),
//要实现的代理类的接口列表
target.getClass().getInterfaces(),
//将方法调用分配给代理类
handler);
//通过代理执行方法,会调用handler中的invoke方法
proxy.one();
}
}
结果打印
执行代理类中的invoke方法
调用方法的名称:one
方法增强前
执行 one 方法
方法增强后
CGLIB动态代理
CGLIB动态代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。
优点:
- 基于字节码,生成真实对象的子类
- 运行效率高于JDK代理
- 不需要实现接口
缺点:非JDK功能,需要引入额外的Java包
实现步骤:
- 创建Enhancer实例
- 通过setSuperclass方法来设置目标类
- 通过setCallback方法来设置拦截对象
- create方法生成Target的代理类,并返回代理类的实例
CGLIB代理时代理类去继承目标类,然后重写目标类的方法,这样以保证代理类拥有目标类的同名方法。
实例
使用CGLIB动态代理,肯定要引入cglib-x.x.x.jar,而CGLIB底层用ASM来操作字节码,因此也要引入asm-x.x.x.jar。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
目标类
public class TargetClass {
public String target(String name){
return "hello" + name;
}
}
自定义拦截
public class MyInterceptor implements MethodInterceptor {
/**
Enhancer可能是CGLIB中最常用的一个类,和Java1.3动态代理中引入的Proxy类差不多。
和Proxy不同的是,Enhancer既能够代理普通的class,也能够代理接口。
Enhancer创建一个被代理对象的子类并且拦截所有的方法调用
(包括从Object中继承的toString和hashCode方法)。Enhancer不能够拦截final方法
*/
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class<?> clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("动态代理处理前");
System.out.println("被拦截的方法"+method.getName());
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("结果:"+result);
System.out.println("动态代理处理后");
return result;
}
}
调用
public class MyTest {
public static void main(String[] args) {
TargetClass target = (TargetClass)(new MyInterceptor().getProxy(TargetClass.class));
target.target("我是目标");
}
}
执行结果
动态代理处理前
被拦截的方法target
结果:hello我是目标
动态代理处理后
部分内容来自原文链接:https://blog.csdn.net/FromZeroJiYuan/article/details/121847587