面试整理
设计模式
1)代理模式
对原始类进行功能扩展,但是对外暴漏的接口不变。不改变原始类的功能,只是对功能进行补充。
spring mybatis 中SqlSessionTemplate 代理SqlSession,增加自动事务处理和自动close。
seam 扩展的EntityManager。
实现方式1,使用java.lang.reflect.Proxy.newProxyInstance
Proxy只能对接口生成代理类(动态生成class,比如$proxy13,会根据接口名称缓存,同样的接口只会生成一次class)。
?
public static Object newProxyInstance(ClassLoader loader,
??? ??? ??? ??? ??? ? Class<?>[] interfaces,
??? ??? ??? ??? ??? ? InvocationHandler h)
使用方式:创建代理类后直接调用接口的响应方法
this.sqlSessionProxy = (SqlSession) newProxyInstance(xxxClassLoader(),
??????? new Class[] { SqlSession.class },
??????? new SqlSessionInterceptor());
sqlSessionProxy.methodxxx(xxx....);
代理类实际生成的代码中有对应的接口方法,比如methodxxx(xxx....),方法体可能的内容是:只是调用
InvocationHandler public Object invoke(Object proxy, Method method, Object[] args)方法,这样就将控制全
移交到了SqlSessionInterceptor中,Object proxy参数就是动态类实例本身($proxy13的实例),一般情况下
不会使用该参数,在方法中能获取到的信息就是SqlSessionInterceptor实例本身和Method method, Object[] args,如何对实例进行代理呢?只能通过SqlSessionInterceptor实例本身获得要代理的原始类实例,通过SqlSessionInterceptor实例的属性构造出代理类实例或者在直接要代理的实例放入SqlSessionInterceptor中
SqlSessionInterceptor的大概实现如下
。。。
sqlSession=xxxx;//创建sqlSession所需的信息由SqlSessionInterceptor实例本身提供
Object result = method.invoke(sqlSession, args);
afterDoSomething();?
?
下面的示例是在构造代理对象时将要代理的实例放入InvocationHandler中
?