今天安全编程上机,本来以为就是简单的几个Java的小实验,但是在今天这个上机的时候,我第一次听说了JavaBean的内省机制,第一次听说,感觉很新奇,然后就查阅了相关资料发现这个与反射机制有些相关联,所以就想简单的总结一下今天上机的收获。学无止境,果然,学无止境。
个人博客:大碗稀饭
在讲解Java的内省机制之前,然我们来看看Java的反射机制。
反射机制
反射机制的优点:
可以实现动态的创建对象和编译,使代码更加灵活多变,比如在javaWeb方面。在开发的时候我们使用的MySQL,但是如果线上环境需要我们使用Orcale,如果我们实现了反射机制,那么我们只需要修改配置文件就可以了,而不用重新将代码编译一次。
反射机制的缺点:
对性能的影响。使用反射机制基本上是一种解释操纵,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
内省机制
什么是内省机制(或者说使用内省机制的好处):
-
内省的出现有利于了对类对象属性的操作,减少了代码的数量。
-
在计算机科学中,内省是指计算机程序在运行时(Run time)检查对象(Object)类型的一种能力,通常也可以称作运行时类型检查。不应该将内省和反射混淆。相对于内省,反射更进一步,是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。
内省机制与反射的区别:
反射式在运行状态把Java类中的各种成分映射成相应的Java类,可以动态的获取所有的属性以及动态调用任意一个方法,强调的是运行状态。内省机制是通过反射来实现的,BeanInfo用来暴露一个bean的属性、方法和事件,以后我们就可以操纵该JavaBean的属性。
内省技术操作javabean更简单,方便,比如Apache提供的BeanUtils就是和内省技术的原理差不多,而且内省是基于反射的,只是在反射的基础之上封装了,很易于我们操作。
满足内审机制的条件:
- 执行java.io.Serializable 接口
- 提供无参数的构造器
- 提供getter 和 setter方法访问它的属性
内省机制的操作方式:
-
通过Introspector类获得Bean对象的 BeanInfo
-
然后通过 BeanInfo 来获取属性的描述器(PropertyDescriptor)
-
通过这个属性描述器就可以获取某个属性对应的 getter/setter方法
-
然后通过反射机制来调用这些方法
-
通过PropertyDescriptor来操作Bean对象
代码实现:
①使用传统的方式:
//普通的Bean
public class Bean {
private String name;
private Integer age;
public String getName () {
return name;
}
public Integer getAge () {
return age;
}
public void setName (String name) {
this.name = name;
}
public void setAge (Integer age) {
this.age = age;
}
@Override
public String toString () {
return "Bean{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//操作展示
public class Demo {
public static void main (String[] args){}
private static void demo2 () throws Exception {
Bean bean = new Bean();
BeanInfo beanInfo = Introspector.getBeanInfo(Bean.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
//遍历全部方法
for (PropertyDescriptor prop : propertyDescriptors){
if("age".equals(prop.getName())){
Method writeMethod = prop.getWriteMethod();
writeMethod.invoke(bean,100);
}else if("name".equals(prop.getName())){
Method writeMethod = prop.getWriteMethod();
writeMethod.invoke(bean,"哈哈哈");
}
}
System.out.println(bean);
}
private static void demo1 () throws Exception {
Bean bean = new Bean();
PropertyDescriptor propertyDescriptor =
new PropertyDescriptor("name", bean.getClass());
System.out.println(bean);
//相当于使用setName方法
Method writeMethod = propertyDescriptor.getWriteMethod();
writeMethod.invoke(bean,"你好世界");
System.out.println(bean);
//相当于使用getName方法
Method readMethod = propertyDescriptor.getReadMethod();
Object obj = readMethod.invoke(bean);
System.out.println("Bean: "+obj);
}
}
②使用Beanutils来操作
<!--Maven的相关依赖-->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<!--需要使用引入commons-logging不然会报错-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
//普通的Bean
import java.util.Date;
public class Bean {
private String name;
private Integer age;
private Date date;
public String getName () {
return name;
}
public Integer getAge () {
return age;
}
public void setName (String name) {
this.name = name;
}
public void setAge (Integer age) {
this.age = age;
}
public Date getDate () {
return date;
}
public void setDate (Date date) {
this.date = date;
}
@Override
public String toString () {
return "Bean{" +
"name='" + name + '\'' +
", age=" + age +
", date.time=" + date.getTime() +
'}';
}
}
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import java.util.Date;
public class Demo {
public static void main (String[] args) throws Exception {
}
private static void demo3 () throws Exception {
Bean bean = new Bean();
BeanUtils.setProperty(bean,"date",new Date());
BeanUtils.setProperty(bean,"name",12);
System.out.println(bean);
//对于PropertyUtils.setProperty而言,类型不匹配就会报错
//PropertyUtils.setProperty(bean,"name",12);
//System.out.println(bean);
PropertyUtils.setProperty(bean,"age",100);
System.out.println(bean);
//BeanUtils它以字符串的形式对javabean进行转换,
// 而PropertyUtils是以原本的类型对javabean进行操作。
//如果类型不对,就会有argument type mismatch异常。
}
private static void demo2 () throws Exception {
//BeanUtils也支持级联操作
Bean bean = new Bean();
//相当于setDate
BeanUtils.setProperty(bean,"date",new Date());
System.out.println(bean);
//级联操作
BeanUtils.setProperty(bean,"date.time",1000);
System.out.println(bean);
//之所以可以 BeanUtils.setProperty(point, "birth.time", 10000);
// 这样写,那是因为Date类中有getTime()和setTime()方法,
// 即Date类中相当于有time这个属性。
}
private static void demo1 () throws Exception {
Bean bean = new Bean();
//相当于setName
BeanUtils.setProperty(bean,"name","你好呀世界");
//相当于setAge
BeanUtils.setProperty(bean,"age",100);
System.out.println(bean);
//相当于getName
System.out.println(BeanUtils.getProperty(bean,"name"));
//相当于getAge
System.out.println(BeanUtils.getProperty(bean,"age"));
System.out.println(BeanUtils.getProperty(bean,"age").getClass().getName());
//我们看到虽然属性x的类型是Integer,但是我们设置的时候无论是Integer还是String,
// BeanUtils的内部都是当成String来处理的。
}
}
总结
我觉的内省机制其实,是在反射机制上面进一步的封装,让我们在操作JavaBean的时候,使用内省机制,将会进一步简化我们的代码,让操作变得更加简洁,高效。