Spring的xml配置bean文件原理-[Java反射机制]

来源:互联网 发布:手机商城 php 编辑:程序博客网 时间:2024/05/08 23:28
知道Spring在xml文件里面配置bean的方式,但是它是如何将对象赋值过去的呢?就是通过xml解析+Java反射。Xml解析可用jdom或者dom4j。网络上一找一大堆。下面我们就来说说Java的反射和内省:反射:Java ReflectionJava反射机制具有的功能:1、在运行时判断任意一个对象所属的类2、在运行时构造任意一个类的对象3、在运行时判断任意一个类具有的成员标量和方法4、在运行时调用任意一个对象的方法生成动态代理通俗的说:  反射就是让你可以通过名称来得到对象 ( 类,属性,方法 ) 的技术。  例如我们可以通过类名来生成一个类的实例;  知道了方法名,就可以调用这个方法;  知道了属性名就可以访问这个属性的值。 简单的反射案例:Class对象可以做很多操作。Class stu = Class.forName("cn.zhang.model.Student");Constructor[] stus = stu.getDeclaredConstructors();for(int i=0;i<stus.length;i++){System.out.println(stus[i].toString());}//得到实例Student s = (Student) stu.newInstance();1..加载类有三种方法 加载类的3种方法第一种:Class cls1 = Class.forName("cn.csdn.reflect.Student");第二种:Student stu = new Student();Class cls2 = stu.getClass();第三种:Class cls3 = Student.class;2.要解析下面这个类的构造方法public class Student {private String name;private String sex;private int age;//无参构造public Student(){}//带两个参数的构造public Student(String name,int age){this.name=name;this.age=age;}//带一个数组参数的构造public Student(String strs[]){System.out.println(strs.length);}//带一个集合类型参数的构造private Student(List list){System.out.println(list.size());}//一个普通的方法public void study(){System.out.println("good good study day day up");}public String getName(){return name;}}通过 Constructor csr[] = cls.getConstructors();我们可以得到Student 类中所有的构造方法的参数型然后我们遍历这个方法输出构造器参数的类型名称for(Constructor c:csr){//for循环新特性参数解析:(集合里面存放的个体类型 集合的单个对象(自己起名):被遍历的对象集合)//打印出构造器参数的类型及构造器名称 System.out.println(c.toGenericString());}运行的结果如下:public cn.csdn.reflect.Student() // 无参构造 public cn.csdn.reflect.Student(java.lang.String,int) //带有两个参数的构造public cn.csdn.reflect.Student(java.lang.String[])  //带有数组参数的构造 当我们得到所有造器参数的类型及构造器名称我们可以通过以下的方法来解析// 解析无参构造:public Student()public void test1() throws ClassNotFoundException, SecurityException,NoSuchMethodException, IllegalArgumentException,InstantiationException, IllegalAccessException,InvocationTargetException {// 1、加载类Class cls = Class.forName("cn.csdn.reflect.Student");// 2、通过无参数的构造器解析// getConstructor() 方法返回一个 Constructor 对象,它反映此 Class //对象所表示的类的指定公共构造方法。// parameterTypes 参数是 Class 对象的一个数组,这些 Class 对象按声//明顺序标识构造方法的形参类型。Constructor constructor = cls.getConstructor(null);  // 3、创建类的实例 , 通过newInstance() 方法可以创建一个实例 , 这就相当//于 Student entity = new Student();Student entity = (Student) constructor.newInstance(null);        //4、调用对象的方法entity.study();}//解析带有两个参数的构造:public Student(String name,int age);public void test2()throws Exception{//1、加载类Class cls = Class.forName("cn.csdn.reflect.Student");//2、通过带有参数的构造器解析Constructor constructor = cls.getConstructor(String.class,int.class);//3、创建类实例Student entity = (Student)constructor.newInstance("redarmy",90);//4、调用方法entity.study();System.out.println(entity.getName());} //解析数组参数的构造正确的写法:public Student(String strs[])public void test4()throws Exception{//1、加载类Class cls = Class.forName("cn.csdn.reflect.Student");//2、根据构造器参数类型获取相应的构造器对象   Constructor csr = cls.getConstructor(String[].class);String str[]={"111","123"};//3、创建实体对象Student entity = (Student)csr.newInstance((Object)str);//4、调用方法entity.study();} //解析数组参数的构造错误的写法:public Student(String strs[])public void test4()throws Exception{//1、加载类Class cls = Class.forName("cn.csdn.reflect.Student");//2、根据构造器参数类型获取相应的构造器对象   Constructor csr = cls.getConstructor(String[].class);String str[]={"111","123"};//3、创建实体对象Student entity = (Student)csr.newInstance(str);//4、调用方法entity.study();}注意:从上面两个程序我们可以发现前的的程序把这个数组做了一 Object 的造型,这是因为按1.5的语法,整个数组是一个参数,而按1.4的语法,数组中的每个元素是一个参数,当把一个字符串传给它时,JDK1.5 会兼容JDK1.4 的语法,即会按1.4的把数组打散成为若干个单独的参数,JAVAC 只把它当成JDK1.4来解析,不把它当过1.5来解释,因此出现参数类型不对问题当我们加上 Object 时,编译器会作特殊处理,编译器不把参数当成数组看,也就不会打散了。但是问题出现了,我们会发现,那个集合类的构造参数没有打印出来,也就是下面的这个构造//带一个集合类型参数的构造private Student(List list){System.out.println(list.size());}这时我们发现这个构造于其它三个不同,是一个私有的构造public void test5()throws Exception{//1、加载类Class cls = Class.forName("cn.csdn.reflect.Student");//2、根据构造器参数类型获取相应的构造器对象    // getDeclaredConstructor()  这个方法是在private 中 使用的   请不要//和public 中//的  getConstructor() 混淆Constructor csr = cls.getDeclaredConstructor(List.class);// setAccessible(true) 这个方法是暴力解析  因为他是private 声明的构造方法csr.setAccessible(true);//暴力//3、创建实体对象Student entity = (Student)csr.newInstance(new ArrayList());//4、调用方法entity.study();}3解析里的方法我们开始解析下面这个类里的方法public class Student {//无参studay()方法public void studay(){System.out.println("学习中");}//有两个参数的getSum(int a ,int b)方法public int getSum(int a ,int b) {int sum = a + b;return sum;}//静态的主函数public static void main(String[] args) {System.out.println("aaaa");}}我们可以通过getMethods()方法反回一个一个Method[] 类型数组,然后遍历输出@Testpublic void Test() throws Exception {Class cls = Class.forName("cn.csdn.reflect.Student");//用这个方法时操作类必有一个 无参构造Student stu = (Student) cls.newInstance();Method[] ms = cls.getMethods();for(Method m : ms) {System.out.println(m.toGenericString());}}解析: studay() 这个方法@Testpublic void Test1() throws Exception{Class cls = Class.forName("cn.csdn.reflect.Student");Student stu = (Student) cls.newInstance();Method m = cls.getMethod("studay", null);m.invoke(stu, null);}解析:getSum(int a ,int b)方法@Testpublic void Test2() throws Exception{Class cls = Class.forName("cn.csdn.reflect.Student");//加载类Student stu = (Student) cls.newInstance();// 创建类实例Method m = cls.getMethod("getSum", int.class,int.class);//2解析方法int sum = (Integer) m.invoke(stu, 10,10);//执行方法System.out.println(sum);}解析: 主函数 @Testpublic void Test3() throws Exception{Class cls = Class.forName("cn.csdn.reflect.Student");//加载类Student stu = (Student) cls.newInstance();// 创建类实例Method m = cls.getMethod("main", String[].class);//2解析方法m.invoke(stu, (Object)new String[]{"a"});}//简便的方法操作方法@Testpublic void test1()throws Exception{Student st = new Student();//通过构造器 创建 PropertyDescriptor对象PropertyDescriptor pd = new PropertyDescriptor("age", Student.class);Method md = pd.getWriteMethod(); //写操作md.invoke(st, 120);System.out.println(st.getAge());md = pd.getReadMethod();int value = (Integer)md.invoke(st, null); //读操作System.out.println(value);}请大家注意这个强制转成Object这个类型,原因和构造方法的原因一样4.解析里面的字段,属性如果一个字段有get方法我们就说这个字段是这个类的属性public class Student {private String pub;//属性private String  pvt; //属性private String name;// 字段public String getPub() {return pub;}public String getPvt() {return pvt;}}得到所有的字段@Test  // 得到所有的字段getDeclaredFields()public void Test5() throws Exception{Class cls = Class.forName("cn.csdn.reflect.Student");Student stu = (Student) cls.newInstance();Field[]  fd = cls.getDeclaredFields();for(Field f : fd) {System.out.println(f.getName());System.out.println(f.toGenericString());}}对属性赋值取值@Testpublic void Test6() throws Exception{Class cls = Class.forName("cn.csdn.reflect.Student");Student stu = (Student) cls.newInstance();Field fd = cls.getDeclaredField("pvt");fd.setAccessible(true);fd.set(stu, "aa");String s = (String)fd.get(stu);System.out.println(s);System.out.println(stu.getPvt());}内省(xing)Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class object下面我们通过来操作这个类来解释什么是内省public class TestSetGet {private int age;private String name;private String pass;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}}/** 通过Introspector类获得Bean对象的 BeanInfo, 然后通过 BeanInfo 来获取属性的描述器(* PropertyDescriptor ) 通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,* 然后通过反射机制来调用这些方法。*/@Testpublic void test() throws Exception{//得到这个类Class cls = Class.forName("cn.csdn.reflect.TestSetGet");//通过类的newInstance来获取这个类对象TestSetGet tsg = (TestSetGet) cls.newInstance();BeanInfo bi = Introspector.getBeanInfo(TestSetGet.class);PropertyDescriptor[] pd = bi.getPropertyDescriptors();for(PropertyDescriptor p : pd) {System.out.println(p.getName());if(p.getName().equals("age")) {Method m = p.getWriteMethod();m.invoke(tsg, 12);System.out.println("aa===   "+p.getPropertyType());}}System.out.println(tsg.getAge());}//简便的方法@Testpublic void test1()throws Exception{TestSetGet st = new TestSetGet();//通过构造器 创建 PropertyDescriptor对象PropertyDescriptor pd = new PropertyDescriptor("age", TestSetGet.class);Method md = pd.getWriteMethod(); //写操作md.invoke(st, 120);System.out.println(st.getAge());md = pd.getReadMethod();int value = (Integer)md.invoke(st, null); //读操作System.out.println(value);}