概述
反射机制是java中很重要的一环,是与io一样,属于java底层性原理,很多框架的开发的十分依赖反射(比如IOC).反射理解对类进行了''解剖''.
代理与反射恰好相反,对类进行了包装,代理类的行为,在各类框架中应用十分广泛(如AOP,RPC).
反射
反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。(反射)
从基本定义中可以理出关键词:运行中(反射时机),自身(反射对象),内部属性(反射内容),以下仅对反射对象与内容作举例说明.(反射入门)
class
package reflection;
@Deprecated
public class ReflectClass{
public String name;
/**get the default name
* @return
*/
public static String getDefaultName(String name){
return name == null ? "hello world" : name;
}
private void getName(){
System.out.println("private excute");
}
}
test
package reflection;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import org.junit.Test;
public class TestReflect {
@Test
/*
* jdk提供的反射相关类 java.lang.Class;//类 java.lang.reflect.Constructor;//构造器
* java.lang.reflect.Field;//属性 java.lang.reflect.Method;//方法
* java.lang.reflect.Modifier;//修饰符(public private 等)
* java.lang.annotation.Annotation;//注解
*/
public void testBasic() throws Exception {
/*注:对abstract class ,class,interface 都是可以获取到相关declare信息的,但invoke等一些方法只针对实例而言的
* 此处仅以class为例(当class继承class或实现interface,反射的包括继承或实现部分)
*
* */
/* 获取类 ----获取反射对象 */
Class<?> clazz;
// 第一种方式(直接获取):
// java中每个类型都有class属性.
clazz = ReflectClass.class;
/*
* //第二种方式(利用classLoader获取): clazz = Class.forName("ReflectClass");
*
* //第三种方式(实例获取): ReflectClass r = new ReflectClass(); clazz =
* r.getClass();
*/
/* 反射内容 */
/*
* 属性 private String name;
*/
Field[] fields = clazz.getDeclaredFields();
System.out.println("reflect field start");
for (Field field : fields) {
System.out.println("name: " + field.getName());// 属性的名字
System.out.println("modifier: " + Modifier.toString(field.getModifiers()));// 获得属性的修饰符,例如public,static等等
System.out.println("type: " + field.getType().getSimpleName());// 属性的类型的名字
}
System.out.println("****************************");
/*
* 构造器 public ReflectClass(){}
*/
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
System.out.println("reflect constructor start");
for (Constructor<?> constructor : constructors) {
System.out.println("name: " + constructor.getName());// 构造器的名字
System.out.println("modifier: " + Modifier.toString(constructor.getModifiers()));// 获得构造器修饰符,例如public,static等等
System.out.println("parameters: " + Arrays.toString(constructor.getParameterTypes()));// 构造器参数
}
System.out.println("****************************");
/*
* 方法 public static String getDefaultName(String name)
*/
Method[] methods = clazz.getDeclaredMethods();
System.out.println("reflect method start");
for (Method method : methods) {
System.out.println("name: " + method.getName());// 方法的名字
System.out.println("modifier: " + Modifier.toString(method.getModifiers()));// 获得方法修饰符,例如public,static等等
System.out.println("parameters: " + Arrays.toString(method.getParameterTypes()));// 方法参数
}
System.out.println("****************************");
System.out.println("reflect annotation start");
Annotation[] annotations = clazz.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
System.out.println("name: " + annotation.toString());
}
System.out.println("****************************");
System.out.println("invoke private start");
/* 注意:对一些private 修饰,可以获取,但需要进行权限设置(暴力反射)才能执行,以method为例 */
Method method = clazz.getDeclaredMethod("getName");
System.out.println("name: " + method.getName());
method.setAccessible(true);// 设置访问权限
method.invoke(new ReflectClass());
/*
* 打印结果 reflect field start name: name modifier: public type: String
****************************
* reflect constructor start name: reflection.ReflectClass modifier:
* public parameters: []
****************************
* reflect method start name: getName modifier: private parameters: []
* name: getDefaultName modifier: public static parameters: [class
* java.lang.String]
****************************
* reflect annotation start name: @java.lang.Deprecated()
****************************
* invoke private start name: getName private excute
*/
}
}
反射获取类描述,类描述结合代理对象,便可与实现类的相关功能(rpc).
代理
代理:为其他对象提供一种代理已控制对这个对象的访问.(代理)
按照代理的创建的时期,代理分静态代理,动态代理
静态代理
静态代理属于硬编码,在程序运行之前就代理类已经生成,静态代理更多的时候作为一种代理思想而存在.
静态代理example
被代理对象
package proxy;
public class Student {
public void study(){
System.out.println("hello world");
}
}
代理对象
package proxy;
public class StudentProxy {
private Student student;
public StudentProxy (Student student) {
this.student = student;
}
public void study(){
if (student == null) {
System.out.println("proxy fail");
}
student.study();
}
}
访问
public static void main(String[] args) {
StudentProxy proxy = new StudentProxy(new Student());
proxy.study();
}
动态代理
动态代理,在程序运行时,运用反射机制动态创建,相比静态代理,更为灵活,大多数框架底层使用就是动态代理.此处主要讲JDK动态代理与CGLIB代理
JDK动态代理
JDK实现动态代理核心:Proxy代理工具类,InvocationHandler反射实现接口.
JDK动态代理只对实现接口的类有效
增加一个接口
package proxy;
public interface Human{
public void study();
}
接口实现
package proxy;
public class Student implements Human{
public void study(){
System.out.println("hello world");
}
}
client
final Student stu =new Student();
Human s = (Human)Proxy.newProxyInstance(Human.class.getClassLoader(), new Class[] {Human.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
result = method.invoke(stu,args);
return result;
}
});
s.study();
CGLIB代理
JDK动态代理的类必须实现接口,对没有实现接口的类进行代理,使用CGLIB动态代理
基本原理:运行时动态的生成一个被代理类的子类(通过ASM字节码处理框架实现),子类重写了被代理类中所有非final的方法。在子类中采用方法拦截的技术拦截所有父类非final方法的调用,顺势植入横切逻辑。
引入相关包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
目标类
package proxy;
public class CglibTest {
public void doSomething(){
System.out.println("hello");
}
}
client
/*Enhancer类是CGLib中的一个字节码增强器
* 设置父类CglibTest
* 设置方法拦截器(实现AOP)
* enhancer.create()动态生成CglibTest的子类
* */
Enhancer enhancer =new Enhancer();
enhancer.setSuperclass(CglibTest.class);
//方法拦截器,执行子类方法前执行
enhancer.setCallback(new MethodInterceptor() {
/**
* 重写方法拦截在方法前和方法后加入业务
* Object obj为目标对象
* Method method为目标方法
* Object[] params 为参数,
* MethodProxy proxy CGlib方法代理对象
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object result ;
System.out.println("处理前");
result=proxy.invokeSuper(obj, args);
System.out.println("处理后");
return result;
}
});
CglibTest cglibTest=(CglibTest)enhancer.create();
cglibTest.doSomething();
代理总结
- 相对于动态代理,静态代理更被认可为一种思维模式,而动态代理使用反射机制动态创建代理对象
- JDK动态代理(可以用静态的思维去理解),代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他的业务逻辑处理
- CGLIB是生成一个目标对象的子类,覆盖目标对象的所有方法(不包括final方法),通过设置方法拦截器,在调用子类的方法时,进行拦截,实现AOP
- JDK动态代理制能针对实现接口的类实行代理,CGLIBE针对类
- 动态代理在AOP,RPC(rpc小案例)颇多,