引出问题(打印日志为例)
程序运行应该记录运行日志信息,以作记录和分析。
打印日志代码放在实现类UserManagerImp中
UserManagerImpl.java
public class UserManagerImpl implements UserManager {
publicvoid addUser(String userId, String userName) {
System.out.println("start-->>addUser()userId-->>" + userId);
try{
System.out.println("UserManagerImpl.addUser()userId-->>" + userId);
System.out.println("success-->>addUser()");
}catch(Exceptione) {
e.printStackTrace();
System.out.println("error-->>addUser()");
thrownew RuntimeException();
}
}
}
可以看出:
需求变时需要改,对已经测试好的代码开放修改
但代码重复,工作量大,修改时恐怖
引入代理
代理模式是对象的结构型模式,给某一个对象提供了一个代理对象,并由代理对象控制对原对象的引用。其实
代理模式是在访问的对象时引入一定程度的间接性,这种间接性可以附加多种用途——模式其实就是加入间接层。
它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
静态
代理对象在编译阶段被创建
打印日志代码抽出,放在UserManagerProxy
UserManagerImplProxy.java
publicclass UserManagerImplProxy implements UserManager {
privateUserManager userManager;
publicUserManagerImplProxy(UserManager userManager) {
this.userManager= userManager;
}
publicvoid addUser(String userId, String userName) {
try{
System.out.println("start-->>addUser()userId-->>" + userId);
userManager.addUser(userId,userName);
System.out.println("success-->>addUser()");
}catch(Exceptione) {
e.printStackTrace();
System.out.println("error-->>addUser()");
}
}
}
第一个问题倒是解决了——关闭修改了。
但第二个问题——代码重复,工作量大,修改时恐怖,却没有得到解决。
动态
运行时,运用反射机制动态创建而成
打印日志代码放在LogHandler中
LogHandler.java
/**
* 采用动态代理封装日志
* @author TCH
*
*/
publicclass LogHandler implements InvocationHandler {
privateObject targetObject;
publicObject newProxyInstance(Object targetObject) {
this.targetObject= targetObject;
returnProxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
publicObject invoke(Object proxy, Method method, Object[] args)
throwsThrowable {
System.out.println("start-->>"+ method.getName());
for(int i=0; i<args.length; i++) {
System.out.println(args[i]);
}
Objectret = null;
try{
//调用目标方法
ret= method.invoke(targetObject, args);
System.out.println("success-->>"+ method.getName());
}catch(Exceptione) {
e.printStackTrace();
System.out.println("error-->>"+ method.getName());
//分析异常
if(e instanceof InvocationTargetException) {
InvocationTargetExceptionete = (InvocationTargetException)e;
throwete.getTargetException();
}
thrownew ApplicationException("调用目标方法" + method.getName() +" 失败!");
}
returnret;
}
}
- 打印日志的代码可以被提炼出来,因为提供了独立服务,跟添加删除、具体逻辑等操作没关系,但又是公共部分,所以才能提炼出LogHandler。
- 打印日志的代码只维护一份,省事多了,而且出问题几率大大降低。
- JDK动态代理只能对实现了接口的类进行代理,采用JDK动态代理必须实现InvocationHandler接口,采用Proxy类创建相应的代理类。
- InvocationTargetException包装自定义异常
在invoke方法中捕获异常,捕获到的自定义异常被包装在InvocationTargetException中的target属性中。
应用:使用动态代理封装事务,并在BeanFactory中返回代理对象
相当于在工厂和Manager接口间又加了一层,工厂通过代理访问Manager接口,把公共的独立的事务部分放在代理中。所以,模式其实就是加入了一个间接层。
TransactionHandler.java
/**
* 采用动态代理封装事务
* @author Administrator
*
*/
publicclass TransactionHandler implements InvocationHandler {
privateObject targetObject;
publicObject newProxyInstance(Object targetObject) {
this.targetObject= targetObject;
returnProxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
publicObject invoke(Object proxy, Method method, Object[] args)
throwsThrowable {
Connectionconn = null;
Objectret = null;
try{
//从ThreadLocal中取得Connection
conn= ConnectionManager.getConnection();
if(method.getName().startsWith("add") ||
method.getName().startsWith("del")||
method.getName().startsWith("modify")){
//手动控制事务提交
ConnectionManager.beginTransaction(conn);
}
//调用目标对象的业务逻辑方法
ret= method.invoke(targetObject, args);
if(!conn.getAutoCommit()) {
//提交事务
ConnectionManager.commitTransaction(conn);
}
// }catch(ApplicationExceptione) {
// if(!conn.getAutoCommit()) {
// //回滚事务
// ConnectionManager.rollbackTransaction(conn);
// }
// throwe;
}catch(Exceptione) {
e.printStackTrace();
if(e instanceof InvocationTargetException) {
InvocationTargetExceptionete = (InvocationTargetException)e;
throwete.getTargetException();
}
if(!conn.getAutoCommit()) {
//回滚事务
ConnectionManager.rollbackTransaction(conn);
}
throw new ApplicationException("操作失败!");
}finally{
ConnectionManager.closeConnection();
}
returnret;
}
}
BeanFactory.java
/**
* 统一工厂创建和管理对象
* 抽象工厂+单例+反射实现,主要创建两个系列的产品代理:
* 1、Manager系列
* 2、Dao系列产品
* @author TCH
*
*/
publicclass BeanFactory {
// 使用单例维护一个实例
privatestatic BeanFactory instance = new BeanFactory();
privatefinal String beansConfigFile = "beans-config.xml";
//保存Service相关对象
privateMap serviceMap = new HashMap();
//保存Dao相关对象
privateMap daoMap = new HashMap();
privateDocument doc;
// 构造器:读取xml
privateBeanFactory() {
try{
doc= newSAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(beansConfigFile));
}catch (DocumentException e) {
e.printStackTrace();
thrownew RuntimeException();
}
}
// 使用单例维护一个实例
publicstatic BeanFactory getInstance() {
returninstance;
}
/**
* 根据产品编号取得Service系列产品
* @param beanId
* @return
*/
publicsynchronized Object getServiceObject(Class c){
//如果存在相关对象实例,返回
if(serviceMap.containsKey(c.getName())) {
returnserviceMap.get(c.getName());
}
ElementbeanElt = (Element)doc.selectSingleNode("//service[@id=\"" +c.getName() + "\"]");
StringclassName = beanElt.attributeValue("class");
Objectservice = null;
try{
service= Class.forName(className).newInstance();
//采用动态代理包装Service
TransactionHandler transactionHandler = newTransactionHandler();
service = transactionHandler.newProxyInstance(service);
//将创建好多的对象放到Map中
serviceMap.put(c.getName(),service);
}catch (Exception e) {
thrownew RuntimeException();
}
returnservice;
}
/**
* 根据产品编号取得Service系列产品
* @param beanId
* @return
*/
publicsynchronized Object getDaoObject(Class c){
//如果存在相关对象实例,返回
if(daoMap.containsKey(c.getName())) {
returndaoMap.get(c.getName());
}
ElementbeanElt = (Element)doc.selectSingleNode("//dao[@id=\"" +c.getName() + "\"]");
StringclassName = beanElt.attributeValue("class");
Objectdao = null;
try{
dao= Class.forName(className).newInstance();
//将创建好多的对象放到Map中
daoMap.put(c.getName(),dao);
}catch (Exception e) {
thrownew RuntimeException();
}
returndao;
}
}