谈谈Java反射机制,动态代理是基于什么原理?
反射机制
是Java语言提供的一种基础功能,赋予程序在运行时自省(introspect,官方用语)的能力。
通过反射我们可以直接操作类或者对象,比如获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义。
动态代理
是一种方便运行时动态构建代理、动态处理代理方法调用的机制,很多场景都是利用类似机制做到的,比如用来包装RPC调用、面向切面的编程(AOP)。
实现动态代理的方式很多,比如JDK自身提供的动态代理,就是主要利用了上面提到的反射机制。还有其他的实现方式,比如利用传说中更高性能的字节码操作机制,类
似ASM、 cglib(基于ASM)、 Javassist等。
JDK自身提供的动态代理 vs cglib(基于ASM)
JDK Proxy的优势:
- 最小化依赖关系,减少依赖意味着简化开发和维护, JDK本身的支持,可能比cglib更加可靠。
- 平滑进行JDK版本升级,而字节码类库通常需要进行更新以保证在新版Java上能够使用。
- 代码实现简单
cglib框架的优势:
- 有的时候调用目标可能不便实现额外接口,从某种角度看,限定调用者实现接口是有些侵入性的实践,类似cglib动态代理就没有这种限制。
- 只操作我们关心的类,而不必为其他相关类增加工作量。
- 高性能。
反射基本使用相关
获取class类实例方法:
Class clazz = String.class;
Class clazz = "abc".getClass();
Class cl = this.getClass().getClassLoader();
Class clazz = cl.loadClass("类的全类名");
Class clazz = Class.forname("java.lang.String");
基本使用:
public class Person {
private String name;
private String age;
public Person(String name, String age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
demo
public class ReflectDemo {
public static void main(String[] args) {
String name = "reflect.Person";
Class clazz = null;
try {
//1获取类对象
clazz= Class.forName(name);
//2.调用指定参数构造器
Constructor con = clazz.getConstructor(String.class,String.class);
//3.通过Constructor的实例创建对应的类的对象,并且初始化类的属性
Person p2 = (Person) con.newInstance("peter","20");
System.out.println(p2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
打印:
Person{name='peter', age='20'}
还可以获取:
1.实现的全部接口:
public Class<?>[] getInterfaces()
2.继承的父类
public native Class<? super T> getSuperclass();
3.全部的构造器
public Constructor<T>[] getConstructors()
返回此 Class 对象所表示的类的所有public构造方法。
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 对象表示的类声明的所有构造方法。
4.全部的方法
public Method[] getDeclaredMethods()
返回此Class对象所表示的类或接口的全部方法
public Method[] getMethods()
返回此Class对象所表示的类或接口的public的方法
5.全部的Field
public Field[] getFields()
返回此Class对象所表示的类或接口的public的Field。
public Field[] getDeclaredFields()
返回此Class对象所表示的类或接口的全部Field。
- Annotation相关
get Annotation(Class<T> annotationClass)
getDeclaredAnnotations()
7.泛型相关
获取父类泛型类型: Type getGenericSuperclass()
泛型类型: ParameterizedType
获取实际的泛型类型参数数组: getActualTypeArguments()
通过使用:
cons1.setAccessible(true);
setAccessible启动和禁用访问安全检查的开关
就能获取私有的(private)方法,变量等。
JDK代理
public interface UserService {
void addUser();
void updateUser();
}
public class UserServiceImpl implements UserService {
public void addUser() {
System.out.println("add user");
}
public void updateUser() {
System.out.println("updateUser");
}
}
public class MyAspect {
public void before(){
System.out.println("代理 before");
}
public void after(){
System.out.println("代理 after");
}
}
public class MyBeanFactory {
public static UserService createService(){
//1目标类
final UserService userService = new UserServiceImpl();
//切面类
final MyAspect myAspect = new MyAspect();
/**
* 参数1: loader:类加载器,动态代理类,运行时创建,任何类都需要类加载器将其加载到内存。
* 一般情况下:当前类.class.getClassLoader()
* 或者: 目标类.getClass().getClassLoader()
* 参数2: Class[] interfaces 代理类需要实现的接口。
* 方式1:目标示例.getClass().getInterfaces(); 注意,只能获得自己的接口,不能获得父元素的接口
* 方式2: new Class[](UserService.class)
* 例如: jdbc驱动--》DriverManager 获得接口Connection
* 参数3:
* InvocationHandler() 处理类,接口 必须进行实现类
* 提供invoke方法:代理类的每一个方法执行的时候,都将执行一次invoke
* invoke方法中的参数:
* 3.1:Object proxy: 代理对象
* 3.2:Method method: 代理对象当前执行的方法描述对象(反射)
* method.getName()
* method.invoke(对象,实际参数)
* 3.3: Object[] args: 方法的实际参数
*/
//动态代理
UserService proxyService =
(UserService) Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),
userService.getClass().getInterfaces(),
new InvocationHandler() {
//将目标类和参数类结合
public Object invoke(Object proxy,
Method method,
Object[] args) throws Throwable {
myAspect.before();
Object obj = method.invoke(userService,args);
myAspect.after();
return obj;
}
});
return proxyService;
}
}
测试:
public class TestJdk {
@Test
public void demo1(){
UserService userService = MyBeanFactory.createService();
userService.addUser();
userService.updateUser();
}
}
Cglib代理
- 没有接口,只有实现类
- 采用字节码增强框架,在运行的时候创建目标子类,从而对目标类进行增强。
不需要service接口了
public class UserServiceImpl {
public void addUser() {
System.out.println("add user");
}
public void updateUser() {
System.out.println("updateUser");
}
}
public class MyAspect {
public void before(){
System.out.println("代理 before");
}
public void after(){
System.out.println("代理 after");
}
}
public class MyBeanFactory {
public static UserServiceImpl createService() {
//1目标类
final UserServiceImpl userService = new UserServiceImpl();
//2切面类
final MyAspect myAspect = new MyAspect();
//3.代理类 创建目标类的子类
//3.1 核心类
Enhancer enhancer = new Enhancer();
//3.2 确定父类
enhancer.setSuperclass(userService.getClass());
//3.3 设置回调函数,MethodIntercepter 接口等效jdk
/**
* 参数1 2 3 和 jdk invoke一样
* 参数4:方法的代理
*/
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object proxy,
Method method,
Object[] args,
MethodProxy methodProxy) throws Throwable {
myAspect.before();
Object object = method.invoke(userService, args);
//执行代理类的父类,也就是执行目标类(目标类和代理类 父子关系)
// methodProxy.invokeSuper(proxy,args);
myAspect.after();
return object;
}
});
//创建代理
UserServiceImpl proxyService = (UserServiceImpl) enhancer.create();
return proxyService;
}
}
测试类:
public class TestCglib {
@Test
public void demo1(){
UserServiceImpl userService = MyBeanFactory.createService();
userService.addUser();
userService.updateUser();
}
}
参考:
极客时间:《Java核心技术面试精讲》
本笔记根据专栏主题进行学习笔记,虽然参考了许多做了笔记,但是加上了自己的整理,跟原作者的内容可能有很大偏差。如果想查看原版请自行搜索。谢谢