原文来源:http://blog.csdn.net/zhang6622056/article/details/7659489
- 知道Spring在xml文件里面配置bean的方式,但是它是如何将对象赋值过去的呢?就是通过xml解析+Java反射。Xml解析可用jdom或者dom4j。网络上一找一大堆。下面我们就来说说Java的反射和内省:
- 反射:Java Reflection
- Java反射机制具有的功能:
- 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[] 类型数组,然后遍历输出
- @Test
- public 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() 这个方法
- @Test
- public 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)方法
- @Test
- public 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);
- }
- 解析: 主函数
- @Test
- public 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"});
- }
- //简便的方法操作方法
- @Test
- public 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());
- }
- }
- 对属性赋值取值
- @Test
- public 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 方法,
- * 然后通过反射机制来调用这些方法。
- */
- @Test
- public 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());
- }
- //简便的方法
- @Test
- public 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);
- }
相关推荐
Spring依赖注入(Dependency Injection,简称DI)是Java应用开发中的一个重要概念,它是Spring框架的核心特性之一,用于降低组件之间的耦合度,提高代码的可测试性和可维护性。本篇文章将深入探讨Spring依赖注入的...
通过SAXBuilder解析XML,结合反射和Java Bean机制,我们可以手动创建并管理对象的生命周期,实现依赖注入,从而更好地理解Spring的核心机制。在实际项目中,这样的知识有助于优化和调试与Spring相关的代码,提高开发...
在这个特定的"spring IOC反射装载bean"的主题中,我们将深入探讨Spring如何通过XML配置文件来加载和管理Bean,并利用Java的反射机制来实例化这些Bean。 首先,Spring容器通过读取XML配置文件来获取Bean的定义。这些...
首先,Spring解析XML配置文件的过程是由`BeanDefinitionReader`完成的,它负责读取并解析XML文件,生成BeanDefinition对象。Spring提供了多种类型的BeanDefinitionReader,例如`XmlBeanDefinitionReader`,用于处理...
通过阅读这本书和实践提供的JAVA+Spring示例代码,初学者可以深入理解Java反射的原理和Spring IOC的实际应用,从而提高编程技能,更好地应对复杂的项目需求。在学习过程中,务必理论与实践相结合,加深理解,这样...
在基于XML的配置方式中,Spring通过XML文件来配置Bean的定义。在这个文件中,开发者定义需要Spring管理的Bean,并且配置相应的属性和依赖关系。 - 三种实例化Bean的方式: - 使用类构造器实例化:这是最简单的实例...
总的来说,Java反射机制与XML的结合,使得我们在编写代码时可以具有更高的灵活性和动态性,特别是在处理配置文件、插件系统或者需要在运行时动态加载和操作类的情况下。但同时,反射也带来了性能开销和安全风险,...
5. **性能优化**:XMLBean利用了Java的反射机制和内省(Introspection)来提高处理速度。虽然反射有时被认为会影响性能,但在XMLBean中,这种开销被精心设计的缓存机制所抵消,使其在大多数情况下能够提供良好的性能...
在提供的压缩包文件"xml_bean"中,可能包含了示例的XML配置文件和相关的Java类,你可以通过分析这些文件来加深对Java解析XML和模拟Spring IOC的理解。实际项目中,Spring框架提供了更高级的功能,如自动扫描、注解...
"深度解析spring容器管理bean"这一主题,旨在深入理解Spring如何通过反射机制、依赖注入(DI)以及XML或Java配置来实现对Bean的生命周期管理。 首先,Spring容器主要有两种类型:DefaultListableBeanFactory和...
通过XML配置文件或Java配置类,我们可以定义bean的生命周期行为,如初始化方法、销毁方法等。此外,我们还可以利用@Autowired注解自动装配bean的依赖,使得代码更加简洁和可维护。 Spring Boot则是在Spring基础上...
例如,关于IoC(Inversion of Control,控制反转)的实现,Spring使用了XML配置或注解来定义bean的依赖关系,通过反射机制动态加载和管理bean。另外,AOP模块实现了切面编程,允许我们定义横切关注点,如日志、事务...
在纯Java配置下,我们不再需要在servlet-context.xml文件中定义DispatcherServlet、HandlerMapping、HandlerAdapter等组件,而是使用@Configuration和@Bean注解在Java类中声明和配置它们。 **MyBatis** MyBatis是一...
通过dom4j解析配置文件,得到list集合(存放Bean标签的id和class属性) * 3.通过反射实例化得到对应的实例化对象,放置在map中(map是键值对,可根据id获取值)(遍历list获取对应的class属性,利用class。formName...
在Spring中,Bean的定义通常通过XML配置文件完成,例如`beans.xml`。在这个配置文件中,我们可以声明Bean的ID、类名、属性和依赖等信息。当Spring启动时,它会读取这些配置,实例化Bean并建立它们之间的依赖关系。 ...
Spring通过XML配置、注解配置或Java配置三种方式来定义Bean,并进行加载。接下来,我们将详细探讨Spring Bean加载的过程及其相关知识点。 1. **Bean定义**: - XML配置:在`src`目录下的XML配置文件(如`beans.xml...
XML配置文件是Spring配置的核心,它定义了bean的属性、依赖关系和初始化方法等。例如: ```xml <bean id="exampleBean" class="com.example.ExampleBean"> </bean> ``` 在解析XML文件时,我们需要实现一个...
Spring提供多种实例化Bean的方式,这里以`XmlBeanFactory`为例,通过`FileSystemResource`加载XML配置文件,然后通过`getBean`方法获取Bean实例。在`getBean`内部,会根据Bean定义创建并初始化Bean对象,包括执行...
- **显式装配**:可以在XML配置文件中通过`ref`属性来指定依赖的Bean。 - **Java代码中显式装配**:使用`@Configuration`和`@Bean`注解来实现。 - **自动装配**:主要有`byName`和`byType`两种方式。使用`@Autowired...