facet-oriented Programming (AOP)
Aspect Oriented Programming
can be done byPre-compilationSquare-and run-timeDynamic Agentimplementation without modifying theSource Codea technique for adding functionality dynamically and uniformly to a program. AOP is actually GoF The continuation of design patterns, the design pattern of the tireless pursuit of the caller and the callee between the decoupling , increase the flexibility and scalability of your code, AOP can be said to be a realization of this goal.
Key Features
logging, performance statistics, security control, transaction processing, Exception Handling wait
Main intentions
logging, performance statistics, security control, transaction processing, Exception Handling Such code is separated from the business logic code, and through the separation of these behaviors, we want to be able to separate them into non-instructional methods of business logic, and then change these behaviors without affecting the code of the business logic.
Case-Transaction Management
annotation mode, defining transaction switch markers
@Retention (retentionpolicy.runtime) @Target (elementtype.method) public @interface Tran {}
Write a custom annotation on the method that needs to open the transaction
Public interface UserService extends service{/** * Registered user * @param user encapsulates the Userbean */@Tranvoid Regist
Service Implementation Class
Public class userserviceimpl implements userservice { private userdao dao = basicfactory.getfactory (). Getdao (Userdao.class); Public void regist (User user) { try{    //1. Verify that the user name already exists if (Dao.finduserbyname ( User.getusername ())!=null) { throw New runtimeexception ("User name already exists!!");         }        //2. Call the method in DAO to add the user to the database user.setrole ("user"); user.setstate (0); user.setactivecode ( Uuid.randomuuid (). toString ()); dao.adduser (user);         //3. Sending an activation message properties prop = new properties (); prop.setproperty ( "Mail.transport.protocol", "SMTP"); prop.setproperty (" Mail.smtp.host ", " "localhost"); prop.setproperty (" Mail.smtp.auth ", " true "); prop.setproperty (" Mail.debug ", "true"); session session = Session.getinstance (prop); message msg = new mimemessage (session); msg.setfrom (new InternetAddress ("[email protected]"); msg.setrecipient ( Recipienttype.to, new internetaddress (User.getemail ()), msg.setsubject (User.getusername () + ", activation Mail from estore"); msg.settext (User.getusername () + ", click on the link below to activate the account, if not click Please copy to the browser address bar access: HTTP ://www.estore.com/activeservlet?activecode= "+user.getactivecode ()); transport trans = session.gettransport (); Trans.connect ("AA", "123"); trans.sendmessage (msg, Msg.getallrecipients ()); }catch (exception e) { e.printstacktrace (); throw new runtimeexception (e); } }}
Transaction management tool class, transform the data source, determine whether to open the transaction
Public class transactionmanager { private transactionmanager () { } //--data source, this data source is the only one in the entire program private static datasource source = new combopooleddatasource (); --whether to open the tag of the transaction private static threadlocal<boolean> istran_local = new ThreadLocal<Boolean> () { @Override Protected boolean initialvalue () { return false;//--first false, indicating that the transaction is not turned on by default } }; //-- Save the proxy connection for the real connection, and change the Close method private static ThreadLocal<Connection> Proxyconn_local = new threadlocal<connection> () {}; //--Save the real connection private&nbsP;static threadlocal<connection> realconn_local = new threadlocal<connection > () {}; /** * How to open a transaction */ public static void starttran () throws SQLException{ istran_local.set (TRUE);//--set transaction marked as true final connection Conn = source.getconnection ();//--Create a connection, all database operations in the current thread are based on this conn Conn.setautocommit (false);//--Open transaction realconn_local.set (conn);//--to facilitate subsequent closing of the connection, Save this connection in the current thread //--because a transaction needs to execute multiple SQL, each SQL execution closes the connection, so that subsequent SQL is not able to execute, so this local method to transform the Close method, Make him unable to close the connection Connection proxyConn = (Connection) proxy.newproxyinstance (Conn.getclass (). getClassLoader (), conn.getclass (). Getinterfaces () , new invocationhandler () { puBlic object invoke (object proxy, method method, object[] args) throws throwable { if ("Close". Equals (Method.getname ())) { return null; }else{ return method.invoke (Conn, args); } } proxyconn_local.set (proxyConn); } /** * Submit a transaction */ public static void commit () { dbutils.commitandclosequietly (Proxyconn_local.get ()); } /** * Rolling back Transactions */ public static void&nBsp;rollback () { dbutils.rollbackandclosequietly (proxyConn_ Local.get ()); } /** * This method should do : * If a transaction is not turned on, the most common data source is returned * if a transaction is turned on, Returns a data source that has been transformed into a getconnection method, which returns the same open transaction connection * each time @return * @throws SQLException */ public static datasource getsource () throws SQLException{ if (Istran_local.get ()) {//--If a transaction is turned on, the datasource of the transformation is returned, and the getconnection of the same open transaction is returned for each call to conn return (DataSource) proxy.newproxyinstance (Source.getclass (). getClassLoader (), source.getclass (). Getinterfaces () ,new invocationhandler () { public object invoke (OBject proxy, method method, object[] args) throws Throwable { if ("getconnection". Equals (Method.getname ())) { Return proxyconn_local.get (); }else{ return method.invoke (Source, args); } } }); }else{//--does not open a transaction, return to the normal data source return source; } } /** * Release Resources */ public static void release () { dbutils.closequietly (Realconn_local.get ());//-- The previous connection was not closed at the time of release to really close the connection realconn_local.remove (); proxyconn_ Local.remove (); istran_local.remove (); }}
Service,dao's Factory class
Generate service agents, based on annotations to determine what to do before and after the service method executes
public class basicfactory { private static basicfactory Factory = new basicfactory (); private static properties Prop = null; private basicfactory () {} static{ try { prop = new properties (); prop.load (New filereader (BasicFactory.class.getClassLoader () getresource (" Config.properties "). GetPath ()); } catch (Exception e) { e.printstacktrace (); throw new runtimeexception (E ); } } public static basicfactory getfactory () { return factory; } /** * Get Service methods */ @SuppressWarnings ("unchecked") public <t extends service> t getservice (Class<T> clazz) { try{ //--create a specific service based on the configuration file string infname = clazz.getsimplename (); string implname = prop.getproperty (InfName); final T service = (T) class.forname (implname). Newinstance (); //--in order to implement AOP, generate service proxies, based on annotations to determine what to do before and after the service method executes, such as: Transaction management/logging/fine-grained permission control .... T proxyService = (T) proxy.newproxyinstance ( Service.getclass (). getClassLoader (), service.getclass (). Getinterfaces () , new invocationhandler () { // Control transaction public object invoke According to annotations (Object proxy, method method,object[] args) throws Throwable { if (Method.isannotationpresent (Tran.class)) {//If there is an annotation, manage the transaction: try{ Transactionmanager.starttran ();//--Open Transaction object obj = method.invoke(Service, args);//--Real Execution Method Transactionmanager.commit ();//--COMMIT TRANSACTION return obj; }catch ( Invocationtargetexception e) { transactionmanager.rollback ();//--ROLLBACK TRANSACTION throw new runtimeexception ( E.gettargetexception ()); } catch (exception e) { transactionmanager.rollback ();//--ROLLBACK TRANSACTION throw nEw runtimeexception (e); }finally{ Transactionmanager.release ();//--release resources } }else{//without annotations, do not manage transactions, execute methods directly return method.invoke (Service, args); } } }); return proxyService; }catch (Exception e) { e.printstacktrace (); &nBsp; throw new runtimeexception (e); } } /** * ways to get DAO */ public <t extends dao> t getdao (Class<t> clazz) { Try{ string infname = clazz.getsimplename (); string implname = prop.getproperty (InfName); return (T) class.forname (implname). newinstance (); }catch (exception e) { e.printstacktrace () ; throw new runtimeexception (e); } }}
There's no need to think about transactions in DAO.
Public class userdaoimpl implements userdao { public void adduser (User user) { string sql = "insert into users values (null,?,?,?,?,?,?,?, null)"; try{ QueryRunner Runner = new queryrunner (Transactionmanager.getsource ()); runner.update (Sql,user.getusername (), User.getpassword (), User.getNickname () , User.getemail (), User.getrole (), User.getstate (), User.getactivecode ()); }catch (exception e) { e.printstacktrace (); throw new runtimeexceptIon (E); } } Public user finduserbyname (String username) { String sql = "SELECT&NBSP;*&NBSP;FROM&NBSP;USERS&NBSP;WHERE&NBSP;USERNAME&NBSP;=&NBSP;?"; try{ queryrunner runner = new queryrunner (Transactionmanager.getsource ()); return runner.query (sql, new BeanHandler<User> (User.class), username); }catch (exception e) { E.printstacktrace (); throw new runtimeexception (e); } }}
Programming AOP for Facets