自己編寫IOC控制反轉(zhuǎn)及AOP面向切面
1.概念
IOC:Inversion of control 控制反轉(zhuǎn)
- 控制:指的是對(duì)象創(chuàng)建(實(shí)例化、管理)的權(quán)利
- 反轉(zhuǎn):控制權(quán)交給外部環(huán)境了(spring框架、IoC容器)
- 傳統(tǒng)開發(fā)⽅式:⽐如類A依賴于類B,往往會(huì)在類A中new⼀個(gè)B的對(duì)象
- IoC思想下開發(fā)方式:我們不⽤⾃⼰去new對(duì)象了,⽽是由IoC容器(Spring框架)去幫助我們實(shí)例化對(duì)象并且管理它,我們需要使⽤哪個(gè)對(duì)象,去問IoC容器要即可。
- 解決的問題:解決對(duì)象之間的耦合問題,避免new關(guān)鍵字
- Ioc和DI區(qū)別:IOC和DI是從不同角度描述同一件事情(對(duì)象實(shí)例化及依賴關(guān)系維護(hù)這件事情)。IOC是站在對(duì)象的角度,對(duì)象實(shí)例化及其管理的權(quán)力交給了(反轉(zhuǎn))容器。DI:Dependancy Injection(依賴注⼊),是站在容器的角度,容器會(huì)把對(duì)象依賴的其他對(duì)象注入(送進(jìn)去),比如A對(duì)象實(shí)例化過程中因?yàn)槁暶髁艘粋€(gè)B類型的屬性,那么就需要容器把B對(duì)象注入給A
AOP:Aspect oriented Programming 面向切面編程
- 起源:aop是oop的延續(xù),oop三大特征:封裝、繼承、多態(tài)。是一種垂直縱向的繼承體系。OOP編程思想可以解決⼤多數(shù)的代碼重復(fù)問題,但是有⼀些情況是處理不了的,⽐如在頂級(jí)⽗類中的多個(gè)⽅法中相同位置出現(xiàn)了重復(fù)代碼,OOP就解決不了
- 橫切邏輯代碼問題:1.橫切代碼重復(fù)問題。2.橫切邏輯代碼和業(yè)務(wù)代碼混雜在⼀起,代碼臃腫,維護(hù)不⽅便
- AOP解決的問題:在不改變?cè)袠I(yè)務(wù)邏輯情況下,增強(qiáng)橫切邏輯代碼,根本上解耦合,避免橫切邏輯代碼重復(fù)
- 面向切面編程理解:「切」:指的是橫切邏輯,原有業(yè)務(wù)邏輯代碼我們不能動(dòng),只能操作橫切邏輯代碼,所以⾯向橫切邏輯?!?#12207;」:橫切邏輯代碼往往要影響的是很多個(gè)⽅法,每⼀個(gè)⽅法都如同⼀個(gè)點(diǎn),多個(gè)點(diǎn)構(gòu)成⾯,有⼀個(gè)⾯的概念在⾥⾯
2.通過銀行轉(zhuǎn)賬案例手寫IOC和AOP
2.1.表結(jié)構(gòu)
CREATE TABLE `account` ( `name` varchar(255) DEFAULT NULL COMMENT '用戶名', `money` varchar(255) DEFAULT NULL COMMENT '賬戶金額', `cardNo` varchar(255) NOT NULL COMMENT '銀行卡號(hào)' ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.2.銀行轉(zhuǎn)賬調(diào)用關(guān)系
2.3.分析存在的問題
- (1)問題⼀:在上述案例實(shí)現(xiàn)中,service 層實(shí)現(xiàn)類在使⽤ dao 層對(duì)象時(shí),直接在TransferServiceImpl 中通過 AccountDao accountDao = new JdbcAccountDaoImpl() 獲得了 dao層對(duì)象,然⽽⼀個(gè) new 關(guān)鍵字卻將 TransferServiceImpl 和 dao 層具體的⼀個(gè)實(shí)現(xiàn)類JdbcAccountDaoImpl 耦合在了⼀起,如果說技術(shù)架構(gòu)發(fā)⽣⼀些變動(dòng),dao 層的實(shí)現(xiàn)要使⽤其它技術(shù),⽐如 Mybatis,思考切換起來的成本?每⼀個(gè) new 的地⽅都需要修改源代碼,重新編譯,⾯向接⼝開發(fā)的意義將⼤打折扣?
- (2)問題⼆:service 層代碼沒有竟然還沒有進(jìn)⾏事務(wù)控制 ?!如果轉(zhuǎn)賬過程中出現(xiàn)異常,將可能導(dǎo)致數(shù)據(jù)庫數(shù)據(jù)錯(cuò)亂,后果可能會(huì)很嚴(yán)重,尤其在⾦融業(yè)務(wù)
2.4.解決問題思路
- 實(shí)例化對(duì)象的⽅式除了 new 之外,還有什么技術(shù)?反射 (需要把類的全限定類名配置在xml中)
- 考慮使⽤設(shè)計(jì)模式中的⼯⼚模式解耦合,另外項(xiàng)⽬中往往有很多對(duì)象需要實(shí)例化,那就在⼯⼚中使⽤反 射技術(shù)實(shí)例化對(duì)象,⼯⼚模式很合適
- service 層沒有添加事務(wù)控制,怎么辦?沒有事務(wù)就添加上事務(wù)控制,⼿動(dòng)控制 JDBC 的Connection 事務(wù),但要注意將Connection和當(dāng)前線程綁定(即保證⼀個(gè)線程只有⼀個(gè)Connection,這樣操作才針對(duì)的是同⼀個(gè) Connection,進(jìn)⽽控制的是同⼀個(gè)事務(wù))。分析:數(shù)據(jù)庫的事務(wù)歸根結(jié)底是Connection的事務(wù)connection.commit();提交事務(wù) connection.rollback();回滾事務(wù)
2.5.通過IOC及AOP進(jìn)行改造
2.5.0.pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lagou.edu</groupId> <artifactId>lagou-transfer</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>lagou-transfer Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <!-- 單元測(cè)試Junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- mysql數(shù)據(jù)庫驅(qū)動(dòng)包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.35</version> </dependency> <!--druid連接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.21</version> </dependency> <!-- servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- jackson依賴 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.6</version> </dependency> <!--dom4j依賴--> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <!--xpath表達(dá)式依賴--> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1.6</version> </dependency> <!--引入cglib依賴包--> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.1_2</version> </dependency> </dependencies> <build> <plugins> <!-- 配置Maven的JDK編譯級(jí)別 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>11</source> <target>11</target> <encoding>UTF-8</encoding> </configuration> </plugin> <!-- tomcat7插件 --> <!-- 注意:目前來說,maven中央倉庫還沒有tomcat8的插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/</path> </configuration> </plugin> </plugins> </build> </project>
2.5.1.index.xml
<!doctype html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>轉(zhuǎn)賬匯款</title> <script type="text/javascript" src="js/jquery-3.4.1.min.js"></script> <style type="text/css"> body { background-color:#00b38a; text-align:center; } .lp-login { position:absolute; width:500px; height:300px; top:50%; left:50%; margin-top:-250px; margin-left:-250px; background: #ffffff; border-radius: 4px; box-shadow: 0 0 10px #12a591; padding: 57px 50px 35px; box-sizing: border-box } .lp-login .submitBtn { display:block; text-decoration:none; height: 48px; width: 150px; line-height: 48px; font-size: 16px; color: #fff; text-align: center; background-image: -webkit-gradient(linear, left top, right top, from(#09cb9d), to(#02b389)); background-image: linear-gradient(90deg, #09cb9d, #02b389); border-radius: 3px } input[type='text'] { height:30px; width:250px; } span { font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-east-asian: normal; font-weight: normal; font-stretch: normal; font-size: 14px; line-height: 22px; font-family: "Hiragino Sans GB", "Microsoft Yahei", SimSun, Arial, "Helvetica Neue", Helvetica; } </style> <script type="text/javascript"> $(function(){ $(".submitBtn").bind("click",function(){ var fromAccount = $("#fromAccount").val(); var toAccount = $("#toAccount").val(); var money = $("#money").val(); if(money == null || $.trim(money).length == 0){ alert("sorry,必須輸入轉(zhuǎn)賬金額~"); return; } $.ajax({ url:'/transferServlet', type:'POST', //GET async:false, //或false,是否異步 data:{ fromCardNo:fromAccount.split(' ')[1], toCardNo:toAccount.split(' ')[1], money:money }, timeout:5000, //超時(shí)時(shí)間 dataType:'json', //返回的數(shù)據(jù)格式:json/xml/html/script/jsonp/text success:function(data){ if("200" == data.status){ alert("轉(zhuǎn)賬成功~~~"); }else{ alert("轉(zhuǎn)賬失敗~~~,message:" + data.message); } } }) }) }) //檢查輸入值是否為整數(shù) function checkFormat(obj){ var reg = /^[0-9]+[0-9]*]*$/; if($.trim($(obj).val()).length>0){ if(!reg.test($(obj).val())){ alert("輸入格式錯(cuò)誤!請(qǐng)輸整數(shù)!"); $(obj).val(""); }else{ $(obj).val(parseInt($(obj).val())); } } } </script> </head> <body> <form> <table class="lp-login"> <tr> <td align="right"><span>收款賬戶</span></td> <td align="center"> <input type="text" id="toAccount" value="韓梅梅 6029621011001" disabled></input> </td> </tr> <tr> <td align="right"><span>付款賬戶</span></td> <td align="center"> <input type="text" id="fromAccount" value="李大雷 6029621011000" disabled></input> </td> </tr> <tr> <td align="right"><span>轉(zhuǎn)賬金額</span></td> <td align="center"> <input type="text" id="money" onblur="checkFormat(this)"></input> </td> </tr> <tr align="center"> <td colspan="2"> <a href="javasrcipt:void(0)" rel="external nofollow" class="submitBtn"><span>轉(zhuǎn) 出</span></a> </td> </tr> </table> </form> </body> </html>
2.5.2.beans.xml
<?xml version="1.0" encoding="UTF-8" ?> <beans> <!--id:唯一標(biāo)識(shí), class類的全路徑--> <bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcAccountDaoImpl"> <property name="ConnectionUtils" ref="connectionUtils"></property> </bean> <bean id="transferService" class="com.lagou.edu.service.impl.TransferServiceImpl"> <!--set+ name,將屬性注入--> <property name="AccountDao" ref="accountDao"></property> </bean> <!--配置新增的三個(gè)組件--> <!--連接池工具類--> <bean id="connectionUtils" class="com.lagou.edu.utils.ConnectionUtils"></bean> <!--事務(wù)管理器--> <bean id="transactionManager" class="com.lagou.edu.utils.TransactionManager"> <property name="ConnectionUtils" ref="connectionUtils"></property> </bean> <!--代理對(duì)象工廠--> <bean id="proxyFactory" class="com.lagou.edu.factory.ProxyFactory"> <property name="TransactionManager" ref="transactionManager"></property> </bean> </beans>
2.5.3.工具類
- ConnectionUtils
package com.lagou.edu.utils; import com.alibaba.druid.pool.DruidPooledConnection; import java.sql.Connection; import java.sql.SQLException; /** * 獲取數(shù)據(jù)庫連接工具類 */ public class ConnectionUtils { /* private ConnectionUtils(){} public static ConnectionUtils getInstance(){ return new ConnectionUtils(); }*/ // 1.單例,保證線程獲取到的連接是同一個(gè)。(每次新new ConnectionUtils,那么里面的threadlocal也是新的,connection也是新的) private ThreadLocal<Connection> threadLocal = new ThreadLocal<>(); public Connection getCurrentThreadConn() throws SQLException { Connection connection = threadLocal.get(); if (connection == null){ connection = DruidUtils.getInstance().getConnection(); // 創(chuàng)建完成后一定要設(shè)置回去 threadLocal.set(connection); } return connection; } }
- DruidUtils
package com.lagou.edu.utils; import com.alibaba.druid.pool.DruidDataSource; public class DruidUtils { private DruidUtils(){ } private static DruidDataSource druidDataSource = new DruidDataSource(); static { druidDataSource.setDriverClassName("com.mysql.jdbc.Driver"); druidDataSource.setUrl("jdbc:mysql://localhost:3306/bank"); druidDataSource.setUsername("root"); druidDataSource.setPassword("123456"); } public static DruidDataSource getInstance() { return druidDataSource; } }
- TransactionManager
package com.lagou.edu.utils; import java.sql.Connection; import java.sql.SQLException; /** * 事務(wù)管理器 */ public class TransactionManager { private ConnectionUtils connectionUtils; public void setConnectionUtils(ConnectionUtils connectionUtils) { this.connectionUtils = connectionUtils; } /* private TransactionManager(){} private static TransactionManager transactionManager = new TransactionManager(); public static TransactionManager getInstance(){ return transactionManager; }*/ public void beginTranscation() throws SQLException { Connection conn = connectionUtils.getCurrentThreadConn(); conn.setAutoCommit(false); System.out.println(conn.getAutoCommit() + ":開啟事務(wù)的連接:"+conn); } public void commit() throws SQLException { connectionUtils.getCurrentThreadConn().commit(); System.out.println("提交的連接:"+connectionUtils.getCurrentThreadConn()); } public void rollback() throws SQLException { connectionUtils.getCurrentThreadConn().rollback(); System.out.println("回滾的連接:"+connectionUtils.getCurrentThreadConn()); } }
- JsonUtils
package com.lagou.edu.utils; import java.util.List; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; /** * JSON工具類(使用的是jackson實(shí)現(xiàn)的) */ public class JsonUtils { private static final ObjectMapper MAPPER = new ObjectMapper(); /** * 將對(duì)象轉(zhuǎn)換成json字符串。 * @param data * @return */ public static String object2Json(Object data) { try { String string = MAPPER.writeValueAsString(data); return string; } catch (JsonProcessingException e) { e.printStackTrace(); } return null; } /** * 將json結(jié)果集轉(zhuǎn)化為對(duì)象 * * @param jsonData json數(shù)據(jù) * @param beanType 對(duì)象中的object類型 * @return */ public static <T> T json2Pojo(String jsonData, Class<T> beanType) { try { T t = MAPPER.readValue(jsonData, beanType); return t; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 將json數(shù)據(jù)轉(zhuǎn)換成pojo對(duì)象list * @param jsonData * @param beanType * @return */ public static <T>List<T> json2List(String jsonData, Class<T> beanType) { JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType); try { List<T> list = MAPPER.readValue(jsonData, javaType); return list; } catch (Exception e) { e.printStackTrace(); } return null; } }
2.5.4.pojo
- Account
package com.lagou.edu.pojo; public class Account { private String cardNo; private String name; private int money; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } public String getCardNo() { return cardNo; } public void setCardNo(String cardNo) { this.cardNo = cardNo;} @Override public String toString() { return "Account{" + "cardNo='" + cardNo + '\'' + ", name='" + name + '\'' + ", money=" + money + '}'; } }
2.5.5.工廠類
- BeanFactory
package com.lagou.edu.factory; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 工廠類 * 作用1:解析xml文件,使用反射技術(shù)實(shí)例化bean對(duì)象,放入map中待用; * 作用2:提供接口方法根據(jù)id從map中獲取bean(靜態(tài)方法) * */ public class BeanFactory { private static Map<String,Object> map = new HashMap<>(); // 0.服務(wù)一啟動(dòng),就將對(duì)象加載至容器中,這里使用靜態(tài)代碼塊 static{ // 1.解析對(duì)象配置文件 InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml"); try { // 使用dom4j技術(shù),首先獲取根節(jié)點(diǎn) <beans> Element rootElement = new SAXReader().read(resourceAsStream).getRootElement(); // 使用xpath,尋找 <bean > 節(jié)點(diǎn) List<Element> beanList = rootElement.selectNodes("http://bean"); for (Element element : beanList) { String id = element.attributeValue("id"); String aClass = element.attributeValue("class"); // 2.使用反射技術(shù),根據(jù)類的全路徑創(chuàng)建對(duì)象 Class<?> aClass1 = Class.forName(aClass); Object o = aClass1.newInstance(); // 3.將解析后的對(duì)象放入容器中(map) map.put(id,o); } // 遍歷property標(biāo)簽,將屬性注入,維護(hù)bean之間的依賴關(guān)系 List<Element> propertyList = rootElement.selectNodes("http://property"); for (Element element : propertyList) { String name = element.attributeValue("name"); String ref = element.attributeValue("ref"); // 使用反射技術(shù),設(shè)置屬性 Element parent = element.getParent(); String parentId = parent.attributeValue("id"); Object parentObj = map.get(parentId); Method[] methods = parentObj.getClass().getMethods(); // 獲取所有方法,尋找set+name,將ref設(shè)置 for (Method method : methods) { if(method.getName().equalsIgnoreCase("set"+name)){ Object propertyObj = map.get(ref); method.invoke(parentObj,propertyObj); } } // 維護(hù)依賴關(guān)系后重新將bean放入map中 map.put(parentId,parentObj); } } catch (DocumentException | ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } // 3.提供獲取對(duì)象的方法 public static Object getBean(String id){ return map.get(id); } }
- ProxyFactory
package com.lagou.edu.factory; import com.lagou.edu.utils.TransactionManager; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * * 代理對(duì)象工廠:生成代理對(duì)象的 */ public class ProxyFactory { private TransactionManager transactionManager; public void setTransactionManager(TransactionManager transactionManager) { this.transactionManager = transactionManager; } /*private ProxyFactory(){ } private static ProxyFactory proxyFactory = new ProxyFactory(); public static ProxyFactory getInstance() { return proxyFactory; }*/ /** * Jdk動(dòng)態(tài)代理 * @param obj 委托對(duì)象 * @return 代理對(duì)象 */ public Object getJdkProxy(Object obj) { // 獲取代理對(duì)象 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; try{ // 開啟事務(wù)(關(guān)閉事務(wù)的自動(dòng)提交) transactionManager.beginTranscation(); result = method.invoke(obj,args); // 提交事務(wù) transactionManager.commit(); }catch (Exception e) { e.printStackTrace(); // 回滾事務(wù) transactionManager.rollback(); // 拋出異常便于上層servlet捕獲 throw e; } return result; } }); } /** * 使用cglib動(dòng)態(tài)代理生成代理對(duì)象 * @param obj 委托對(duì)象 * @return */ public Object getCglibProxy(Object obj) { return Enhancer.create(obj.getClass(), new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { Object result = null; try{ // 開啟事務(wù)(關(guān)閉事務(wù)的自動(dòng)提交) transactionManager.beginTranscation(); result = method.invoke(obj,objects); // 提交事務(wù) transactionManager.commit(); }catch (Exception e) { // 回滾事務(wù) transactionManager.rollback(); e.printStackTrace(); // 拋出異常便于上層servlet捕獲 throw e; } return result; } }); } }
2.5.6.dao層
- AccountDao
package com.lagou.edu.dao; import com.lagou.edu.pojo.Account; public interface AccountDao { Account queryAccountByCardNo(String cardNo) throws Exception; int updateAccountByCardNo(Account account) throws Exception; }
- JdbcAccountDaoImpl
package com.lagou.edu.dao.impl; import com.lagou.edu.pojo.Account; import com.lagou.edu.dao.AccountDao; import com.lagou.edu.utils.ConnectionUtils; import com.lagou.edu.utils.DruidUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; public class JdbcAccountDaoImpl implements AccountDao { private ConnectionUtils connectionUtils; public void setConnectionUtils(ConnectionUtils connectionUtils) { this.connectionUtils = connectionUtils; } public void init() { System.out.println("初始化方法....."); } public void destory() { System.out.println("銷毀方法......"); } @Override public Account queryAccountByCardNo(String cardNo) throws Exception { //從連接池獲取連接 // Connection con = DruidUtils.getInstance().getConnection(); // 從當(dāng)前線程中獲取連接池對(duì)象 Connection con = connectionUtils.getCurrentThreadConn(); String sql = "select * from account where cardNo=?"; PreparedStatement preparedStatement = con.prepareStatement(sql); preparedStatement.setString(1,cardNo); ResultSet resultSet = preparedStatement.executeQuery(); Account account = new Account(); while(resultSet.next()) { account.setCardNo(resultSet.getString("cardNo")); account.setName(resultSet.getString("name")); account.setMoney(resultSet.getInt("money")); } resultSet.close(); preparedStatement.close(); // con.close(); // 不能將當(dāng)前線程的連接關(guān)閉了,不然同個(gè)線程同個(gè)業(yè)務(wù)中其他更新方法獲取的連接就不是同一個(gè) return account; } @Override public int updateAccountByCardNo(Account account) throws Exception { // 從連接池獲取連接 // 改造為:從當(dāng)前線程當(dāng)中獲取綁定的connection連接 // Connection con = DruidUtils.getInstance().getConnection(); // 從當(dāng)前線程中獲取連接池對(duì)象 Connection con = connectionUtils.getCurrentThreadConn(); String sql = "update account set money=? where cardNo=?"; PreparedStatement preparedStatement = con.prepareStatement(sql); preparedStatement.setInt(1,account.getMoney()); preparedStatement.setString(2,account.getCardNo()); int i = preparedStatement.executeUpdate(); preparedStatement.close(); // con.close(); return i; } }
2.5.7.service層
- TransferService
package com.lagou.edu.service; public interface TransferService { void transfer(String fromCardNo,String toCardNo,int money) throws Exception; }
- TransferServiceImpl
package com.lagou.edu.service.impl; import com.lagou.edu.dao.AccountDao; import com.lagou.edu.pojo.Account; import com.lagou.edu.service.TransferService; import com.lagou.edu.utils.TransactionManager; public class TransferServiceImpl implements TransferService { // private AccountDao accountDao = new JdbcAccountDaoImpl(); // private AccountDao accountDao = (AccountDao) BeanFactory.getBean("accountDao"); // 最佳狀態(tài) private AccountDao accountDao; // 構(gòu)造函數(shù)傳值/set方法傳值 public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } @Override public void transfer(String fromCardNo, String toCardNo, int money) throws Exception { // try { // // 開啟事務(wù)(設(shè)置自動(dòng)提交關(guān)閉) // TransactionManager.getInstance().beginTranscation(); Account from = accountDao.queryAccountByCardNo(fromCardNo); Account to = accountDao.queryAccountByCardNo(toCardNo); from.setMoney(from.getMoney()-money); to.setMoney(to.getMoney()+money); accountDao.updateAccountByCardNo(to); int c = 1/0; accountDao.updateAccountByCardNo(from); // 事務(wù)提交 // TransactionManager.getInstance().commit(); // }catch (Exception e){ // // 事務(wù)回滾 // TransactionManager.getInstance().rollback(); // throw e; // } } }
2.5.8.controller層
- TransferServlet
package com.lagou.edu.servlet; import com.lagou.edu.factory.BeanFactory; import com.lagou.edu.factory.ProxyFactory; import com.lagou.edu.service.impl.TransferServiceImpl; import com.lagou.edu.utils.JsonUtils; import com.lagou.edu.pojo.Result; import com.lagou.edu.service.TransferService; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name="transferServlet",urlPatterns = "/transferServlet") public class TransferServlet extends HttpServlet { // 1. 實(shí)例化service層對(duì)象 // private TransferService transferService = new TransferServiceImpl(); // private TransferService transferService = (TransferService) BeanFactory.getBean("transferService"); // 從工廠獲取委托對(duì)象,使用代理對(duì)象,主要增加了事務(wù)控制 private ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory"); private TransferService transferService = (TransferService) proxyFactory.getJdkProxy((TransferService) BeanFactory.getBean("transferService")); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 設(shè)置請(qǐng)求體的字符編碼 req.setCharacterEncoding("UTF-8"); String fromCardNo = req.getParameter("fromCardNo"); String toCardNo = req.getParameter("toCardNo"); String moneyStr = req.getParameter("money"); int money = Integer.parseInt(moneyStr); Result result = new Result(); try { // 2. 調(diào)用service層方法 transferService.transfer(fromCardNo,toCardNo,money); result.setStatus("200"); } catch (Exception e) { e.printStackTrace(); result.setStatus("201"); result.setMessage(e.toString()); } // 響應(yīng) resp.setContentType("application/json;charset=utf-8"); resp.getWriter().print(JsonUtils.object2Json(result)); } }
2.5.9.注意事項(xiàng)
com.lagou.edu.utils.ConnectionUtils#getCurrentThreadConn中一定要注意,第一次獲取連接為空時(shí),創(chuàng)建連接后要設(shè)置到當(dāng)前線程中。
if (connection == null){ connection = DruidUtils.getInstance().getConnection(); // 創(chuàng)建完成后一定要設(shè)置回去 threadLocal.set(connection); }
總結(jié)
本篇介紹了IOC和AOP的思想,以及通過一個(gè)案例來進(jìn)行解釋說明,希望對(duì)大家有所幫助,更多相關(guān)手寫IOC和AOP代碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis源碼解析之Transaction事務(wù)模塊
這篇文章主要介紹了MyBatis源碼解析之Transaction事務(wù)模塊,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10IDEA中配置多個(gè)版本的JDK的實(shí)現(xiàn)示例
IDEA可以配置多個(gè)JDK,根據(jù)需要使用不同版本的,本文就來介紹一下IDEA中配置多個(gè)版本的JDK的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03關(guān)于springboot集成swagger及knife4j的增強(qiáng)問題
這篇文章主要介紹了springboot集成swagger以及knife4j的增強(qiáng),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03Hystrix?Dashboard斷路監(jiān)控儀表盤的實(shí)現(xiàn)詳細(xì)介紹
這篇文章主要介紹了Hystrix?Dashboard斷路監(jiān)控儀表盤的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-09-09SpringBoot數(shù)據(jù)校驗(yàn)功能的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot數(shù)據(jù)校驗(yàn)功能的實(shí)現(xiàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02