(一) 内省
- javaBean
内省(Introspector)为了更好的操作Java对象的属性,将具备一定特征的java类当javaBean来看
javaBean类的特征对私有属性提供公共获取和设置方法,而且getter和setter方法除去set和get前缀外相同
javaBean类的一个属性只提供getter或只提供setter则说明该属性只读或只写
将符合javaBean特征的类封装成javaBean后,他的实例对象称之为值对象(Value Object)
一个JavaBean类可以不当JavaBean类的方式处理属性信息,也可以用普通普通类方式处理属性信息
那么可以利用javaBean的操作方式进行处理java对象属性信息,提高效率
如类A中有属性age 而且分别提供getAge和setAge进行获取和设置属性值
属性age在类A中被定义为私有的,设置和获取属性则通过提供的公共方法来进行
这样A就符合javaBean特点,故可以利用javaBean的处理方式来进行属性的获取与设置
属性名的获取并不是直接获取符合javaBean的类的属性的实际名称,因为他们可能是
私有的,javaBean属性名是通过符合javaBean的类提供的setter和getter方法来获取的
- 获取的属性的取名规则
- 获取的属性的取名规则
去掉getter和setter的get或set前缀,然后剩余的单词如果第二个字母是小写 , 则得到的属性名的第一个字母也小写,后面的字母不变,如果第二个字母是大写 , 则得到的属性名的第一个字母也大写,后面的字母不变.
- 属性读写方法名规则
- 属性读写方法名规则
除了boolean类型的属性的getter是 "Is属性名" 外其他类型的属性的getter setter 都根据原java类
- java.beans 包
- java.beans 包
java.beans包中提供了获取某个符合javaBean特点的类的BeanInfo信息的类Introspector ,以及通过BeanInfo获取属性描述器PropertyDescriptor,通过属性描述器就可以获取某个属性对应的getter 和 setter方法 ,从而可以进行反射调用这些方法
- 获取属性描述器有两种途径
- 获取属性描述器有两种途径
一种是直接用属性描述器的构造方法直接创建一种是通过Introspector获取BeanInfo再通过BeanInfo获取属性描述器PropertyDescriptor
通过第一种方式获取的属性描述器是对应于构造方法中指定的某一个属性而通过第二种方式获取的是属性描述器数组,即有多少个属性就得到多少个属性描述器每个属性描述器对应于一个属性
PropertyDescriptor 提供了三种构造方法 , 都要求给出指定的类的属性名的字符串形式
PropertyDescriptor(String propertyName, Class<?> beanClass)
----通过给定的类的某一属性名和该类的Class对象来构造 PropertyDescriptor。
PropertyDescriptor(String propertyName, Class<?> beanClass, String readMethodName, String writeMethodName)----通过给定的类的某一属性名和用于读写属性的方法名称以及该类的Class对象,构造 PropertyDescriptor。
PropertyDescriptor(String propertyName, Method readMethod, Method writeMethod)----通过给定的类的某一属性名以及用来读取和写入属性的方法的 Method 对象构造。
通过第二种途径步骤:
Person ps = new Person(2,"hello");
//1 ,通过Introspector来获取bean对象的beaninfo
BeanInfo bi= Introspector.getBeanInfo(Person.class);
//2.通过beaninfo来获得属性描述器(propertyDescriptor)
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
//3.通过属性描述器来获得对应的get/set方法
for(PropertyDescriptor pd:pds)
{
//5.获得字段名和类型
System.out.println("属性名为:"+pd.getName()+" 属性类型:"+pd.getPropertyType());
// 6.获得PropertyDescriptor对象的写方法
Method mw = pd.getWriteMethod();
//7.获得PropertyDescriptor对象的写方法
Method mr = pd.getReadMethod();
//8.反射调用PropertyDescriptor对象的读写方法
if(pd.getName().equals("name"))
{
mw.invoke(ps,"nihao");//写
System.out.println(mr.invoke(ps));//读
}
else if(pd.getName().equals("age"))
{
mw.invoke(ps,90);//写
System.out.println(mr.invoke(ps));//读
}
}
(二) 代理
- 代理模式
代理的概念:
代理模式是常见的java设计模式之一,
代理就是对一个类进行代理或托管或者说加壳包装 ,提供额外的处理或不同的操作
在实际对象与调用者之间, 插入一个代理对象 ,额外的操作需要与实际对象进行
通信 . 当程序运行的时候不直接调用目标类的对应功能,而通过代理类,由代理类决定是否要
执行被代理的类.java 代理是面向接口的代理,代理类与被代理类实现了同一个接口
代理的特征:
代理类与目标类实现了同样的接口,代理类主要负责为目标类预处理消息、过滤消息、
把消息转发给目标类,以及事后处理消息等。代理类与目标类之间通常会存在关联关系,一
个代理类的对象与一个目标类的对象关联,代理类的对象本身并不真正实现服务,而是通过
调用目标类的对象的相关方法,来提供特定的服务。
代理类的功能:
- 代理类可以分别为目标类的各个方法添加额外的功能相当于给目标类进行特定的包装
在客户端不是直接引用目标类或代理类实例而是用接口引用,接口引用变量可以引用
代理类实例也可以引用目标类实例
之间起到中介作用 , 通过代理类有效地控制对目标类对象的直接访问,也可以很好的隐藏和保
- 代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能代码
- 代理模式的主要作用是 为目标对象提供一种代理, 以控制对这个对象的访问,代理对象可以在客户端和目标对象
护目标类对象,为实现不同的控制策略预留了空间,提高了灵活性.
代理模式的三个角色:
- 抽象角色:真实对象和代理对象的共同接口;
- 代理角色:公共接口的实现类,代理对象角色内部持有真实对象的引用,从而可以操
作真实对象 ,利用持有的真实对象的引用对真实对象特定方法进行封装修
饰, 在执行真实对象操作前后添加其他操作
每个代理的方法对于接口来说是实现,对于真实角色来说是装饰
- 真实角色:公共接口的实现类,代理角色所代表的真实对象,是最终要引用的目标对象
客户端:
需要创建一个真实角色对象,然后将其引用传给代理类,通过调用代理类封装有
真实角色的方法来达到间接执行真实对象的特定方法的目的
如果事先不知道真实角色,如何实现代理,可以通过java的动态代理实现
- 动态代理
代理按代理的创建时期分两种:
静态代理:由程序员创建或特定工具自动生成源代码,再对其进行编译.
在程序运行前,代理类的class文件已经存在了
动态代理:在程序运行时,通过反射机制动态创建
其实现主要通过是java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。
Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现
(1)InvocationHandler 接口只有一个方法
Object invoke(Object proxy, Method method, Object[] args)throws Throwable
参数:
proxy - 代理类实例
method - 被代理的方法的 Method 实例。
args - 被代理方法参数的数组,如果接口方法不使用参数,则为 null
基本类型的参数被包装在对应的包装类中
(2) Proxy :该类即为动态代理类
构造方法
Protected Proxy(InvocationHandler h):传入InvocationHandler实现类的实例,创建代理类实例
静态方法
static Class getProxyClass (ClassLoader loader, Class[] interfaces)
----由提供的定义代理类的类装载器loader和代理类要实现的接口的数组interfaces[]
获得一个代理类的Class对象 ,如果当前存在在获取,如果不存在则创建
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):
----创建代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接
口中声明过的方法)。
static boolean isProxyClass(Class<?> cl)
---- 当且仅当指定的类通过 getProxyClass 方法或 newProxyInstance
方法动态生成为代理类时,返回 true ,用来判断指定的类是否是动态代理类。
static InvocationHandler getInvocationHandler(Object proxy)
---- 返回指定代理实例的调用处理程序。
动态代理的特点:
通过动态代理方式,被代理的对象可以在运行时动态改变,需要控制的接口可以在运行时改变,
控制的方式也可以动态改变,从而实现了非常灵活的动态代理关系。
JVM在运行时动态生成的类称为动态类,动态类必须实现一个或多个接口,所以
JVM生成的动态类只能用作具有相同接口的目标类的代理\
CGLIB库可以动态生成一个类的子类,如果要为一个没有实现接口的类生成
动态代理类,则可以使用CGLIB库
代理类的各个方法除了会调用目标类相应方法和对外返回目标方法返回结果外
还可以在代理方法中的四个位置加上系统功能代码:
-->在调用目标方法之前
-->在调用目标方法之后
-->在调用目标方法前后
-->在处理目标方法异常的catch块中
动态代理创建:
- 1,创建实现接口InvocationHandler的类,该实现类必须实现invoke方法
- 2,创建被代理的类以及接口
- 3,通过Proxy的静态方法newProxyInstance(ClassLoader loader,class[] interfaces , InvocationHandler handler)
获得一个动态代理类对象
- 4,通过动态代理对象调用方法
java动态代理是在运行时生成的class对象,在生成时必须提供一组或一个interface给他,然后
该class就
一个动态代理和一个InvocationHandler 实现关联,每一个动态代理实例的调用都需要通过
InvocationHandler接口的handler来调用,动态代理不做任何操作,只是在创建动态代理时把需要实现的接口和
handler 关联,动态代理需要帮助被代理执行的任务转移给handler来执行,
创建动态类的对象
-->反射得到构造方法
-->实现InvocationHandler接口
-->用构造方法动态创建动态类对象 ,将InvocationHandler的实现类传入
-->改用匿名内部类实现InvocationHandler传给构造方法创建动态代理类
动态生成的类的内部代码
每调用一次动态代理类的方法时都涉及三个要素:即invoke中的三个参数(被代理的类对象,对象的对应方法,该方法的参数)
每次调用一个代理类的方法时都是在调用代理类中的InvocationHandler的对象的invoke方法而在invoke方法中又向目标类发送请求
- 面向方面的编程
系统中存在交叉业务:安全 事务 日志
StudentService ----|----------------|------------------|--------
CourseService ----|----------------|------------------|--------
MiscService ----|----------------|------------------|--------
交叉业务的代码描述:
method1 method2 method3
{ { {
----------------------------------------------------------------------------切面
.... .... ... ... . ...
----------------------------------------------------------------------------切面
} } }
交叉业务的编程问题即为面向方面的编程(AOP),AOP的目的是使交叉业务模块化,
将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的效果
相同 如下:
----------------------------------------------------------------------------切面
dail() dail() dail()
{ { {
.... ... . ... .... ...
} } }
---------------------------------------------------------------------------切面
- 代理模式与装饰模式
装饰模式的特点:
装饰模式可以在不创建更多子类的情况下,对对象的功能加以扩展
装饰模式通过被装饰的类的一个子类对象,把客户端的调用委派到被装饰类
装饰模式对被装饰类的功能扩展完全是透明的
装饰模式的角色:
抽象角色:利用一个抽象接口来规范要附加责任的对象
具体角色:定义将要附加责任的类
装饰角色:持有抽象角色的一个实例,并定义一个与抽象角色接口一直的接口
具体装饰角色:负责给抽象角色加上附加责任
装饰模式的优缺点:
1),装饰模式与继承的目的都是扩展对象的功能,
但装饰模式比继承更具灵活性
2)通过不同的装饰类及装饰类的排列组合可以创造不同的行为组合
3)具体更大的灵活性,但意味着
代理模式与装饰模式的区别:
代理模式与装饰模式很像 , 代理类和装饰类都实现基础对象所实现的接口,
在代理类对象和装饰类对象中都持有着对被代理/被装饰的对象引用,在其内部
利用持有的引用调用目标对象的某方法的前后干点别的事情
装饰模式为装饰的对象增强功能,代理模式为代理的目标对象施加访问控制
装饰在于为目标类添加色彩, 代理在于隐藏目标类.
装饰模式以对客户端透明的方式扩展了对象的功能,是继承关系不灵活的替补方案
代理模式给目标对象提供一个代理对象并用代理对象来控制对目标对象的访问