———–android培训、java培训、java学习型技术博客、期待与您交流!————
1
(1)内省
1、内省对应的英文单词为IntroSpector,英文意思是检查、视察、体检之意,对于程序即对内部进行检查,了解更多的底层细节。
2、内省的作用:主要针对JavaBean进行操作。
(2)JavaBean
1、简述:
1)JavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要用于访问私有的字段,且方法符合某种特殊的命名规则。
2)它是一种特殊的Java类,其中的方法符合特殊的规则。只要一个类中含有get或is和set打头的方法,就可以将其当做JavaBean使用。
3)字段和属性:
字段就是我们定义的一些成员变量,如private String name;等
JavaBean的属性是根据其中的setter和getter方法来确定的,而不是依据其中的变量,如方法名为setId,则中文意思是设置Id,getId也是如此;去掉set或者get前缀,剩余部分就是属性名称。如果剩余部分的第二个字母小写,则把剩余部分改为小写。如:getAge/setAge-->age;gettime-->time;setTime-->time;getCPU-->CPU。
总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。
2、作用:
如果要在两个模板之间传递多个信息,可将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO),这些信息在类中用私有字段来储存,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。
3、JavaBean的好处:
一个符合JavaBean特点的类当做普通类一样可以使用,但是把它当做JavaBean类用会带来一些额外的好处:
1)在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作,别人都这么用和要求这么做,那你就没什么挑选的余地!
2)JDK中提供了对JavaBean进行操作的API,这套API称为内省,若要自己通过getX的方式来访问私有x,可用内省这套API,操作JavaBean要比使用普通的方式更方便。
通过例子来看看,JavaBean的使用方法:
package IntroSpector;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class properDescriptor1
{
public static void main(String[] args) throws Exception
{
//创建Persion对象
Persion p1=new Persion(25, "史今");
//声明想要访问Persion类中的哪些私有属性
String propertyName1="age";
String propertyName2="name";
/*这是得到私有属性age
PropertyDescriptor pd1=new PropertyDescriptor(propertyName1, p.getClass());
Method getMethodName=pd1.getReadMethod();
Object value1=getMethodName.invoke(p);
System.out.println(value1);
这是得到私有属性name
PropertyDescriptor pd2=new PropertyDescriptor(propertyName2, p.getClass());
Method getMethodAge=pd2.getReadMethod();
Object value2=getMethodAge.invoke(p);
System.out.println(value2);
*/
//得到PropertyDescriptor
getMethod(p1, propertyName1);//结果为:25
getMethod(p1, propertyName2);//结果为:史今
//同样的道理也可以设置私有属性
setMethod(p1, propertyName1,30);//参数,为p1对象的propertyName1属性,设置为:30
setMethod(p1, propertyName2,"伍六一");//参数,为p1对象的propertyName2属性,设置为:伍六一
}
//通过该方法把得到属性的方法,抽取成一个方法,小技巧,选中上边的得到其中一个私有属性的代码块,快捷键alt+shift+m,即可抽取
private static void getMethod(Persion p1, String propertyName1) throws IntrospectionException, IllegalAccessException, InvocationTargetException
{
PropertyDescriptor propertyDescriptor=new PropertyDescriptor(propertyName1, p1.getClass());
//通过PropertyDescriptor对象调用该类的方法:
Method getMethod=propertyDescriptor.getReadMethod();
Object valObject=getMethod.invoke(p1);
System.out.println(valObject);
}
//通过方法,设置私有属性的值
private static void setMethod(Persion p, String propertyName,Object args) throws IntrospectionException, IllegalAccessException, InvocationTargetException
{
PropertyDescriptor propertyDescriptor=new PropertyDescriptor(propertyName, p.getClass());
Method setMethod=propertyDescriptor.getWriteMethod();
setMethod.invoke(p, args);//设置属性值
getMethod(p, propertyName);//在此调用getMethod方法显示各个私有属性值
}
}
通过另一种方法操作JavaBean:
先来了解一个接口:BeanInfo
此接口中的一个方法–PropertyDescriptor[] getPropertyDescriptors()
可以返回一个propertyDescriptor数组
怎么得到这个接口的对象:需要另一个类:Introspector
此类中的一个方法
public static BeanInfo getBeanInfo(Class
package IntroSpector;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
public class propertyDescriptor
{
public static void main(String[] args) throws Exception
{
Persion p=new Persion(20,"袁郎");
String propertyName1="name";
String propertyName2="age";
BeanInfo beanInfo=Introspector.getBeanInfo(p.getClass());
PropertyDescriptor[] pds=beanInfo.getPropertyDescriptors();
for(PropertyDescriptor pd:pds)
{
if(pd.getName().equals(propertyName1))
{
Method getMethodName=pd.getReadMethod();
Object value1=getMethodName.invoke(p);
System.out.println(value1);
break;
}
}
}
}
2
动态代理:
静态代理
1,生活中的代理:
武汉人从武汉的代理商手中买联想电脑和直接跑到北京传智播客旁边来找联想总部买电脑,你觉得最终的主体业务目标有什么区别吗?基本上一样吧,都解决了核心问题,但是,一点区别都没有吗?从代理商那里买真的一点好处都没有吗?虽然多花了几百元钱,但自己不用也得到了好处,不用坐车到北京,节约了时间和金钱。
2,程序中的代理:
需求:要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理、日志、计算方法的运行时间、事务管理、等等,你准备如何做?
解决方法:编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类、还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易。
面向方面的编程:
1.系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面
2.交叉业务的编程问题即为面向方面的编程(Aspectoriented program ,简称AOP),AOP的目标就是要使交叉业务模块化。可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的。
3.使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。
二、动态代理:
著名的框架spring中的核心技术aop就使用了动态代理技术。
出现的原因:要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情!写成百上千个代理类,是不是太累!
概念:JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
1,JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
2,CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
3,代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中
创建动态类的实例对象的步骤:
1、用反射获得构造方法
2、编写一个最简单的InvocationHandler类
3、调用构造方法创建动态类的实例对象,并将编写的InvocationHandler类的实例对象传进去
4、打印创建的对象和调用对象的没有返回值的方法和getClass方法,演示调用其他有返回值的方法报告了异常。
5、将创建动态类的实例对象的代理改成匿名内部类的形式编写,锻炼大家习惯匿名内部类。
简单的应用:
package proxyTest;
/*查看,proxy类的class文件上有哪些属性
*
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
//为接口:collection做一个动态代理类
public class ProxyDemo
{
public static void main(String[] args)
{
//创建动态代理类,的字节码:
Class clazzProxy=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
//查看该字节码身上的都有什么属性:
//构造方法:(得到是:Proxy类的构造方法)
Constructor[] constructors=clazzProxy.getConstructors();
for(Constructor constructor: constructors)
{
System.out.println(constructor);
}
System.out.println("-------------");
//成员方法:
Method[] methods=clazzProxy.getMethods();
for(Method method:methods)
{
System.out.println(method);
}
System.out.println("-------------");
//成员变量:
Field[] fields=clazzProxy.getFields();
for(Field field:fields)
{
System.out.println(field);
}
}
}
综合应用:
package proxyTest;
import java.lang.reflect.Method;
//这是需要插入的功能模块的接口
public interface Advace
{
void beforMehtod(Method method);
void aftermethod(Method method);
}
----------
package proxyTest;
//这是实现了要插入的模块功能接口Advace的类
import java.lang.reflect.Method;
public class Myadvace implements Advace
{
long befortime;
long aftertime;
@Override
public void beforMehtod(Method method)
{
befortime=System.currentTimeMillis();
}
@Override
public void aftermethod(Method method)
{
aftertime=System.currentTimeMillis();
System.out.println(method.getName()+" 运行的时间是:"+(aftertime-befortime));
}
}
----------
package proxyTest;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
/*
* 创建代理类的实例:
*/
public class proxyTest1
{
public static void main(String[] args) throws Exception
{
// Class clazzProxy=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
//
// //得到构造方法:
// Constructor proxyConstructor=clazzProxy.getConstructor(InvocationHandler.class);
// //通过构造方法,得到实例对象
//
// Collection proxyCollection=(Collection )proxyConstructor.newInstance(new InvocationHandler()
// {
// ArrayList target=new ArrayList();
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
// {
//
// return method.invoke(target, args);
// }
// });
//上边的两段代码,可以用一个更简单的方法得到;(下面的代码就可以实现)
final ArrayList target=new ArrayList();//被代理的目标对象
//调用getProxy方法,得到动态代理类
Collection proxy=(Collection)getProxy(target,new Myadvace());
//调用代理的add方法,和size方法
proxy.add("sdfsd");
proxy.add("sdfsd");
proxy.add("sdfsd");
System.out.println(proxy);
System.out.println(proxy.size());
}
private static Object getProxy(final Object target, final Advace advace)
{
Object proxyCollection1= Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
advace.beforMehtod(method);
Object retVal= method.invoke(target, args);
advace.aftermethod(method);
return retVal;
}
});
return proxyCollection1;
}
}