JDK代理和CGLib动态代理
JDK代理和CGLib
- jdk代理好处是不需要导入第三方jar包。但目标对象必须实现接口,是基于接口实现。利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
- CGLib基于第三方jar包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。所以该类或方法最好不要声明成final。
代码实现
注解:
用于判断那些方法需要代理,或不需要代理
package com.example.java_test.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
}
接口:
package com.example.java_test.proxy;
import com.example.java_test.annotation.Test;
public interface UserService {
void queryAll();
// 当为JDK动态代理时,拿到的是接口上的注解
@Test
void saveUser();
}
接口实现:
package com.example.java_test.proxy.impl;
import com.example.java_test.annotation.Test;
import com.example.java_test.proxy.UserService;
public class UserServiceImpl implements UserService {
@Override
public void queryAll() {
System.out.println("查询出所有的学生。。。。。");
}
@Override
// CGLib代理时,拿到的是此处的注解
@Test
public void saveUser() {
System.out.println("保存学生信息");
}
}
JDK代理类:
package com.example.java_test.proxy;
import com.example.java_test.annotation.Test;
import com.example.java_test.proxy.impl.UserServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxyTest implements InvocationHandler {
/**
* 目标对象
*/
private Object target;
public Object newProxy(Object target){
//接收业务实现类对象参数
this.target = target;
//通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
//创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// String name = method.getName();
// if (!name.equals("queryAll")){
// method.invoke(target,args);
//
// }else {
// System.out.println("调用方法前的操作");
// method.invoke(target,args);
// System.out.println("调用方法后的操作");
// }
Test[] annotationsByType = method.getAnnotationsByType(Test.class);
if (annotationsByType.length > 0){
System.out.println("调用方法前的操作");
method.invoke(target,args);
System.out.println("调用方法后的操作");
}else {
method.invoke(target,args);
}
return null;
}
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
JDKProxyTest proxyTest = new JDKProxyTest();
UserService proxy = (UserService)proxyTest.newProxy(userService);
proxy.queryAll();
}
}
CGLib代理实现类:
package com.example.java_test.proxy;
import com.example.java_test.annotation.Test;
import com.example.java_test.proxy.impl.UserServiceImpl;
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 CGLibProxyTest implements MethodInterceptor {
private Object target;//业务类对象,供代理方法中进行真正的业务方法调用
//相当于JDK动态代理中的绑定
public Object getInstance(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 {
// 获取方法上的注解
Test[] annotation = method.getAnnotationsByType(Test.class);
if (annotation != null) {
//调用业务类(父类中)的方法
methodProxy.invokeSuper(o, objects);
} else {
System.out.println("处理之前的操作");
//调用业务类(父类中)的方法
methodProxy.invokeSuper(o, objects);
System.out.println("调用后操作");
}
return null;
}
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
CGLibProxyTest proxyTest = new CGLibProxyTest();
UserServiceImpl proxy = (UserServiceImpl) proxyTest.getInstance(userService);
proxy.queryAll();
}
}
当我们代理时,可能不会对类中所有的方法进行代理,可能只是对其中的一部分功能增强,可以根据方法名,或者是注解去实现部分增强。