In the previous blog, I introduced how to use threadlocal to maintain the connection. The biggest advantage of this is that you do not need to transmit the connection back and forth, however, we will find that when we use transactions, we will inevitably write a lot of repeated code, which is irrelevant to the business logic:
Connection conn = connectionmanage. getconnection (); connectionmanage. begintransaction (conn); connectionmanage. committransaction (conn); // and so on. // As well as transaction rollback in catch, closing the connection in finally, etc.
Not only unreasonable, but also repetitive work. One principle of program development is to put an end to repetitive work and achieve good encapsulation.
Here, we use dynamic proxies to encapsulate transactions, so that the business logic layer no longer displays the relevant transaction code.
Package COM. hanyi. DRP. util; import Java. lang. reflect. invocationhandler; import Java. lang. reflect. invocationtargetexception; import Java. lang. reflect. method; import Java. lang. reflect. proxy; import Java. SQL. connection;/*** use dynamic proxy to encapsulate Transactions * @ author hanyi **/public class transactionhandler implements invocationhandler {private object targetobject; /*** get the proxy of the target class * @ Param targetobject * @ return */public object Newproxyinstance (Object targetobject) implements this.tar GetObject = targetobject; return proxy. newproxyinstance (targetobject. getclass (). getclassloader (), targetobject. getclass (). getinterfaces (), this);}/*** proxy method. Call this method before calling the target Class Method */@ overridepublic object invoke (Object proxy, method, object [] ARGs) throws throwable {connection conn = NULL; object ret = NULL; try {// obtain the connection from threadlocal. Connectionmanage is the encapsulation of connection. Conn = connectionmanage. getconnection (); // if it is a method starting with ADD, Del, modify, the transaction if (method. getname (). startswith ("add") | method. getname (). startswith ("Del") | method. getname (). startswith ("modify") {// manually control the connectionmanage of the transaction commit. begintransaction (conn);} // call the business logic method of the target object ret = method. invoke (targetobject, argS); // if the transaction is manually committed, the transaction if (! Conn. getautocommit () {// submit the connectionmanage transaction. committransaction (conn) ;}} catch (exception e) {// if the transaction is submitted manually, roll back the transaction manually if (! Conn. getautocommit () {// roll back the connectionmanage of the transaction. rollbacktransaction (conn);} e. printstacktrace (); If (E instanceof invocationtargetexception) {invocationtargetexception ete = (invocationtargetexception) E; throw ete. gettargetexception ();} Throw new exception ("operation failed! ") ;}Finally {// close the connectionmanage. closeconnection () ;}return RET ;}}
Principle: when we get the business logic layer objects in the factory, what we get is not the target object, but the proxy of the target object. The proxy enables and submits the management transaction for us, roll back, and close
Packaging business logic objects with dynamic proxies in the factory
Public synchronized object getservicebean (Class C) {If (servicemap. containskey (C. getname () {return servicemap. get (C. getname ();} element beanele = (element) Doc. selectsinglenode ("// service [@ ID = \" "+ C. getname () + "\"] "); string classname = beanele. attributevalue ("class"); // system. out. print (classname); object servicebean = NULL; try {servicebean = Class. forname (classname ). newinstance (); // use dynamic proxy to package service transactionhandler = new transactionhandler (); // obtain proxy servicebean = transactionhandler. newproxyinstance (servicebean); servicemap. put (C. getname (), servicebean);} catch (exception e) {Throw new runtimeexception ();} return servicebean ;}In the specific use process, the obtained object is not the target object, but the proxy of the target object.
userManager = (UserManager) getBeanFactory().GetServiceBean(UserManager.class);
Encapsulate transactions using dynamic proxies