手寫Spring框架之AOP

簡(jiǎn)介
前面兩篇博客已經(jīng)實(shí)現(xiàn)了Bean容器, IOC功能和MVC功能, 本篇博客來(lái)實(shí)現(xiàn)AOP功能和事務(wù)管理.?
定義注解
(1) 切面注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public?@interface?Aspect {
????/**
?????* 包名
?????*/
????String?pkg() default?"";
????/**
?????* 類名
?????*/
????String?cls() default?"";
}(2) 事務(wù)注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface?Transactional {
}搭建代理框架
毫無(wú)疑問(wèn)這個(gè)代理框架是基于動(dòng)態(tài)代理實(shí)現(xiàn)的, 但加了一個(gè)鏈?zhǔn)酱淼墓δ? 目的是為了解決多重代理的問(wèn)題, 也就是目標(biāo)對(duì)象的方法被多次增強(qiáng).
(1) Proxy接口
我們自定義了一個(gè)最上層的代理接口, 其中doProxy()執(zhí)行的是鏈?zhǔn)酱? 具體詳情可以看后面的介紹.
public?interface?Proxy?{
????/**
?????* 執(zhí)行鏈?zhǔn)酱?br mpa-from-tpl="t">?????* 所謂鏈?zhǔn)酱? 就是說(shuō), 可將多個(gè)代理通過(guò)一條鏈子串起來(lái), 一個(gè)個(gè)地去執(zhí)行, 執(zhí)行順序取決于添加到鏈上的先后順序
?????*/
????Object doProxy(ProxyChain proxyChain) throws Throwable;
}(2) ProxyChain類
這是一個(gè)代理鏈類, proxyList 存儲(chǔ)的是代理列表(也就是增強(qiáng)列表), 當(dāng)執(zhí)行doProxyChain() 方法時(shí)會(huì)按照順序執(zhí)行增強(qiáng), 最后再執(zhí)行目標(biāo)方法.
public?class?ProxyChain?{
????private?final?Class> targetClass; //目標(biāo)類
????private?final?Object targetObject; //目標(biāo)對(duì)象
????private?final?Method targetMethod; //目標(biāo)方法
????private?final?MethodProxy methodProxy; //方法代理
????private?final?Object[] methodParams; //方法參數(shù)
????private?List proxyList = new?ArrayList<>(); //代理列表
????private?int?proxyIndex = 0; //代理索引
????public?ProxyChain(Class> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List proxyList) ?{
????????this.targetClass = targetClass;
????????this.targetObject = targetObject;
????????this.targetMethod = targetMethod;
????????this.methodProxy = methodProxy;
????????this.methodParams = methodParams;
????????this.proxyList = proxyList;
????}
????public?Object[] getMethodParams() {
????????return?methodParams;
????}
????public?Class> getTargetClass() {
????????return?targetClass;
????}
????public?Method getTargetMethod()?{
????????return?targetMethod;
????}
????/**
?????* 遞歸執(zhí)行
?????*/
????public?Object doProxyChain()?throws?Throwable {
????????Object methodResult;
????????if?(proxyIndex < proxyList.size()) {
????????????//執(zhí)行增強(qiáng)方法
????????????methodResult = proxyList.get(proxyIndex++).doProxy(this);
????????} else?{
????????????//目標(biāo)方法最后執(zhí)行且只執(zhí)行一次
????????????methodResult = methodProxy.invokeSuper(targetObject, methodParams);
????????}
????????return?methodResult;
????}
} (3) AspectProxy類
AspectProxy是一個(gè)切面抽象類, 實(shí)現(xiàn)了Proxy接口, 類中定義了切入點(diǎn)判斷和各種增強(qiáng). 當(dāng)執(zhí)行 doProxy() 方法時(shí), 會(huì)先進(jìn)行切入點(diǎn)判斷, 再執(zhí)行前置增強(qiáng), 代理鏈的下一個(gè)doProxyChain()方法, 后置增強(qiáng)等.
public?abstract?class?AspectProxy?implements?Proxy?{
????private?static?final Logger logger = LoggerFactory.getLogger(AspectProxy.class);
????@Override
????public?final Object doProxy(ProxyChain proxyChain) throws Throwable {
????????Object result = null;
????????Class> cls = proxyChain.getTargetClass();
????????Method method = proxyChain.getTargetMethod();
????????Object[] params?= proxyChain.getMethodParams();
????????begin();
????????try?{
????????????if?(intercept(method, params)) {
????????????????before(method, params);
????????????????result = proxyChain.doProxyChain();
????????????????after(method, params);
????????????} else?{
????????????????result = proxyChain.doProxyChain();
????????????}
????????} catch?(Exception e) {
????????????logger.error("proxy failure", e);
????????????error(method, params, e);
????????????throw?e;
????????} finally?{
????????????end();
????????}
????????return?result;
????}
????/**
?????* 開始增強(qiáng)
?????*/
????public?void?begin() {
????}
????/**
?????* 切入點(diǎn)判斷
?????*/
????public?boolean intercept(Method method, Object[] params) throws Throwable {
????????return?true;
????}
????/**
?????* 前置增強(qiáng)
?????*/
????public?void?before(Method method, Object[] params) throws Throwable {
????}
????/**
?????* 后置增強(qiáng)
?????*/
????public?void?after(Method method, Object[] params) throws Throwable {
????}
????/**
?????* 異常增強(qiáng)
?????*/
????public?void?error(Method method, Object[] params, Throwable e) {
????}
????/**
?????* 最終增強(qiáng)
?????*/
????public?void?end() {
????}
}(4) ProxyFactory類
這是一個(gè)代理工廠類, 我們通過(guò)這個(gè)類來(lái)梳理上面的代理邏輯. ?當(dāng)調(diào)用 ProxyFactory.createProxy(final Class targetClass, final List proxyList) 方法來(lái)創(chuàng)建一個(gè)代理對(duì)象后, 每次執(zhí)行代理方法時(shí)都會(huì)調(diào)用 intercept() 方法, 從而創(chuàng)建一個(gè) ProxyChain 對(duì)象, 并調(diào)用該對(duì)象的 doProxyChain() 方法. 調(diào)用doProxyChain()方法時(shí)會(huì)首先遞歸的執(zhí)行增強(qiáng), 最后再執(zhí)行目標(biāo)方法.
public?class?ProxyFactory?{
????/**
?????* 輸入一個(gè)目標(biāo)類和一組Proxy接口實(shí)現(xiàn), 輸出一個(gè)代理對(duì)象
?????*/
????@SuppressWarnings("unchecked")
????public?static? T createProxy(final?Class> targetClass, final?List proxyList) ?{
????????return?(T) Enhancer.create(targetClass, new?MethodInterceptor() {
????????????/**
?????????????* 代理方法, 每次調(diào)用目標(biāo)方法時(shí)都會(huì)先創(chuàng)建一個(gè) ProxyChain 對(duì)象, 然后調(diào)用該對(duì)象的 doProxyChain() 方法.
?????????????*/
????????????@Override
????????????public?Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy)?throws?Throwable {
????????????????return?new?ProxyChain(targetClass, targetObject, targetMethod, methodProxy, methodParams, proxyList).doProxyChain();
????????????}
????????});
????}
} (5) AopHelper 助手類
AopHelper 助手類用來(lái)初始化整個(gè)AOP框架, 邏輯如下:
框架中所有Bean的實(shí)例都是從Bean容器中獲取, 然后再執(zhí)行該實(shí)例的方法, 基于此, 初始化AOP框架實(shí)際上就是用代理對(duì)象覆蓋掉Bean容器中的目標(biāo)對(duì)象, 這樣根據(jù)目標(biāo)類的Class對(duì)象從Bean容器中獲取到的就是代理對(duì)象, 從而達(dá)到了對(duì)目標(biāo)對(duì)象增強(qiáng)的目的.
public final class?AopHelper?{
????private static?final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class);
????static?{
????????try?{
????????????//切面類-目標(biāo)類集合的映射
????????????Map, Set>> aspectMap = createAspectMap();
????????????//目標(biāo)類-切面對(duì)象列表的映射
????????????Map, List<Proxy>> targetMap = createTargetMap(aspectMap);
????????????//把切面對(duì)象織入到目標(biāo)類中, 創(chuàng)建代理對(duì)象
????????????for?(Map.Entry, List<Proxy>> targetEntry : targetMap.entrySet()) {
????????????????Class> targetClass = targetEntry.getKey();
????????????????List<Proxy> proxyList = targetEntry.getValue();
????????????????Object?proxy = ProxyFactory.createProxy(targetClass, proxyList);
????????????????//覆蓋Bean容器里目標(biāo)類對(duì)應(yīng)的實(shí)例, 下次從Bean容器獲取的就是代理對(duì)象了
????????????????BeanHelper.setBean(targetClass, proxy);
????????????}
????????} catch?(Exception e) {
????????????LOGGER.error("aop failure", e);
????????}
????}
????/**
?????* 獲取切面類-目標(biāo)類集合的映射
?????*/
????private static?Map, Set>> createAspectMap() throws Exception {
????????Map, Set>> aspectMap = new?HashMap, Set>>();
????????addAspectProxy(aspectMap);
????????return?aspectMap;
????}
????/**
?????* 獲取普通切面類-目標(biāo)類集合的映射
?????*/
????private static?void?addAspectProxy(Map, Set>> aspectMap) throws Exception {
????????//所有實(shí)現(xiàn)了AspectProxy抽象類的切面
????????Set> aspectClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
????????for?(Class> aspectClass : aspectClassSet) {
????????????if?(aspectClass.isAnnotationPresent(Aspect.class)) {
????????????????Aspect aspect = aspectClass.getAnnotation(Aspect.class);
????????????????//與該切面對(duì)應(yīng)的目標(biāo)類集合
????????????????Set> targetClassSet = createTargetClassSet(aspect);
????????????????aspectMap.put(aspectClass, targetClassSet);
????????????}
????????}
????}
????/**
?????* 根據(jù)@Aspect定義的包名和類名去獲取對(duì)應(yīng)的目標(biāo)類集合
?????*/
????private static?Set> createTargetClassSet(Aspect aspect) throws Exception {
????????Set> targetClassSet = new?HashSet>();
????????// 包名
????????String?pkg = aspect.pkg();
????????// 類名
????????String?cls = aspect.cls();
????????// 如果包名與類名均不為空,則添加指定類
????????if?(!pkg.equals("") && !cls.equals("")) {
????????????targetClassSet.add(Class.forName(pkg + "."?+ cls));
????????} else?if?(!pkg.equals("")) {
????????????// 如果包名不為空, 類名為空, 則添加該包名下所有類
????????????targetClassSet.addAll(ClassUtil.getClassSet(pkg));
????????}
????????return?targetClassSet;
????}
????/**
?????* 將切面類-目標(biāo)類集合的映射關(guān)系 轉(zhuǎn)化為 目標(biāo)類-切面對(duì)象列表的映射關(guān)系
?????*/
????private static?Map, List<Proxy>> createTargetMap(Map, Set>> aspectMap) throws Exception {
????????Map, List<Proxy>> targetMap = new?HashMap, List<Proxy>>();
????????for?(Map.Entry, Set>> proxyEntry : aspectMap.entrySet()) {
????????????//切面類
????????????Class> aspectClass = proxyEntry.getKey();
????????????//目標(biāo)類集合
????????????Set> targetClassSet = proxyEntry.getValue();
????????????//創(chuàng)建目標(biāo)類-切面對(duì)象列表的映射關(guān)系
????????????for?(Class> targetClass : targetClassSet) {
????????????????//切面對(duì)象
????????????????Proxy?aspect = (Proxy) aspectClass.newInstance();
????????????????if?(targetMap.containsKey(targetClass)) {
????????????????????targetMap.get(targetClass).add(aspect);
????????????????} else?{
????????????????????//切面對(duì)象列表
????????????????????List<Proxy> aspectList = new?ArrayList<Proxy>();
????????????????????aspectList.add(aspect);
????????????????????targetMap.put(targetClass, aspectList);
????????????????}
????????????}
????????}
????????return?targetMap;
????}
} (6) HelperLoader 類
在手寫Spring之MVC這篇博客里我們定義了這個(gè)類, 目的是為了集中加載 ClassHelper, BeanHelper, IocHelper, ControllerHelper 這四個(gè)助手類, 這里還要再加上個(gè) AopHelper 類.
public?final?class?HelperLoader?{
????public?static?void?init()?{
????????Class>[] classList = {
????????????ClassHelper.class,
????????????BeanHelper.class,
????????????AopHelper.class,
????????????IocHelper.class,
????????????ControllerHelper.class
????????};
????????for?(Class> cls : classList) {
????????????ClassUtil.loadClass(cls.getName());
????????}
????}
}AOP實(shí)例
我們創(chuàng)建一個(gè)監(jiān)控接口性能的切面, 當(dāng)接口被調(diào)用后, 打印接口的執(zhí)行時(shí)間.
(1) 業(yè)務(wù)類
public?interface?IUserService?{
????List getAllUser();
}
@Service
public?class?UserService?implements?IUserService?{
????/**
?????* 獲取所有用戶
?????*/
????public?List getAllUser() {
????????List userList = new?ArrayList<>();
????????userList.add(new?User(1, "Tom", 22));
????????userList.add(new?User(2, "Alic", 12));
????????userList.add(new?User(3, "Bob", 32));
????????try?{
????????????Thread.sleep(1000L);
????????} catch?(InterruptedException e) {
????????????e.printStackTrace();
????????}
????????return?userList;
????}
} (2) 處理器
@Controller
public?class?UserController?{
????@Autowired
????private?IUserService userService;
????/**
?????* 用戶列表
?????* @return
?????*/
????@RequestMapping(value = "/userList", method = RequestMethod.GET)
????public?View getUserList()?{
????????List userList = userService.getAllUser();
????????return?new?View("index.jsp").addModel("userList", userList);
????}
} (3) 接口性能監(jiān)控切面
目標(biāo)類是 com.tyshawn.controller 包下的 UserController, 切入點(diǎn)是 getUserList() 方法. 日志記錄切入點(diǎn)方法的執(zhí)行時(shí)間.
@Aspect(pkg = "com.tyshawn.controller", cls = "UserController")
public?class?EfficientAspect?extends?AspectProxy?{
????private?static?final?Logger LOGGER = LoggerFactory.getLogger(EfficientAspect.class);
????private?long?begin;
????/**
?????* 切入點(diǎn)判斷
?????*/
????@Override
????public?boolean?intercept(Method method, Object[] params)?throws?Throwable {
????????return?method.getName().equals("getUserList");
????}
????@Override
????public?void?before(Method method, Object[] params)?throws?Throwable {
????????LOGGER.debug("---------- begin ----------");
????????begin = System.currentTimeMillis();
????}
????@Override
????public?void?after(Method method, Object[] params)?throws?Throwable {
????????LOGGER.debug(String.format("time: %dms", System.currentTimeMillis() - begin));
????????LOGGER.debug("----------- end -----------");
????}
}(4) 結(jié)果
http://localhost:8081/handwritten/userList
---------- begin ----------
time: 1001ms
----------- end -----------事務(wù)管理
我們要達(dá)到的目的是, 當(dāng)我們?cè)谀繕?biāo)方法上加 @Transactional 注解后, 該方法就擁有了事務(wù)管理. 用AOP實(shí)現(xiàn)的思路就是, 前置增強(qiáng)為開啟事務(wù), 后置增強(qiáng)為提交事務(wù), 異常增強(qiáng)為回滾事務(wù).
(1) DatabaseHelper 助手類
DatabaseHelper 為數(shù)據(jù)庫(kù)操作助手類, 可以通過(guò)該助手類進(jìn)行增刪改查, 事務(wù)等一系列的數(shù)據(jù)庫(kù)操作.
public?final class?DatabaseHelper?{
????private?static?final Logger LOGGER = LoggerFactory.getLogger(DatabaseHelper.class);
????private?static?final ThreadLocal CONNECTION_HOLDER;
????private?static?final QueryRunner QUERY_RUNNER;
????private?static?final BasicDataSource DATA_SOURCE;
????static?{
????????CONNECTION_HOLDER = new?ThreadLocal();
????????QUERY_RUNNER = new?QueryRunner();
????????DATA_SOURCE = new?BasicDataSource();
????????DATA_SOURCE.setDriverClassName(ConfigHelper.getJdbcDriver());
????????DATA_SOURCE.setUrl(ConfigHelper.getJdbcUrl());
????????DATA_SOURCE.setUsername(ConfigHelper.getJdbcUsername());
????????DATA_SOURCE.setPassword(ConfigHelper.getJdbcPassword());
????}
????/**
?????* 獲取數(shù)據(jù)源
?????*/
????public?static?DataSource getDataSource() {
????????return?DATA_SOURCE;
????}
????/**
?????* 獲取數(shù)據(jù)庫(kù)連接
?????*/
????public?static?Connection getConnection() {
????????Connection conn = CONNECTION_HOLDER.get();
????????if?(conn == null) {
????????????try?{
????????????????conn = DATA_SOURCE.getConnection();
????????????} catch?(SQLException e) {
????????????????LOGGER.error("get connection failure", e);
????????????????throw?new?RuntimeException(e);
????????????} finally?{
????????????????CONNECTION_HOLDER.set(conn);
????????????}
????????}
????????return?conn;
????}
????/**
?????* 開啟事務(wù)
?????*/
????public?static?void?beginTransaction() {
????????Connection conn = getConnection();
????????if?(conn != null) {
????????????try?{
????????????????conn.setAutoCommit(false);
????????????} catch?(SQLException e) {
????????????????LOGGER.error("begin transaction failure", e);
????????????????throw?new?RuntimeException(e);
????????????} finally?{
????????????????CONNECTION_HOLDER.set(conn);
????????????}
????????}
????}
????/**
?????* 提交事務(wù)
?????*/
????public?static?void?commitTransaction() {
????????Connection conn = getConnection();
????????if?(conn != null) {
????????????try?{
????????????????conn.commit();
????????????????conn.close();
????????????} catch?(SQLException e) {
????????????????LOGGER.error("commit transaction failure", e);
????????????????throw?new?RuntimeException(e);
????????????} finally?{
????????????????CONNECTION_HOLDER.remove();
????????????}
????????}
????}
????/**
?????* 回滾事務(wù)
?????*/
????public?static?void?rollbackTransaction() {
????????Connection conn = getConnection();
????????if?(conn != null) {
????????????try?{
????????????????conn.rollback();
????????????????conn.close();
????????????} catch?(SQLException e) {
????????????????LOGGER.error("rollback transaction failure", e);
????????????????throw?new?RuntimeException(e);
????????????} finally?{
????????????????CONNECTION_HOLDER.remove();
????????????}
????????}
????}
????/**
?????* 查詢實(shí)體
?????*/
????public?static? T queryEntity(Class entityClass, String sql, Object... params ) {
????????T entity;
????????try?{
????????????Connection conn = getConnection();
????????????entity = QUERY_RUNNER.query(conn, sql, new?BeanHandler(entityClass), params);
????????} catch?(SQLException e) {
????????????LOGGER.error("query entity failure", e);
????????????throw?new?RuntimeException(e);
????????}
????????return?entity;
????}
????/**
?????* 查詢實(shí)體列表
?????*/
????public?static? List queryEntityList(Class entityClass, String sql, Object... params ) {
????????List entityList;
????????try?{
????????????Connection conn = getConnection();
????????????entityList = QUERY_RUNNER.query(conn, sql, new?BeanListHandler(entityClass), params);
????????} catch?(SQLException e) {
????????????LOGGER.error("query entity list failure", e);
????????????throw?new?RuntimeException(e);
????????}
????????return?entityList;
????}
????/**
?????* 執(zhí)行更新語(yǔ)句(包括:update、insert、delete)
?????*/
????public?static?int?update(String sql, Object... params) {
????????int?rows;
????????try?{
????????????Connection conn = getConnection();
????????????rows = QUERY_RUNNER.update(conn, sql, params);
????????} catch?(SQLException e) {
????????????LOGGER.error("execute update failure", e);
????????????throw?new?RuntimeException(e);
????????}
????????return?rows;
????}
????/**
?????* 插入實(shí)體
?????*/
????public?static? boolean insertEntity(Class entityClass, Map fieldMap ) {
????????if?(MapUtils.isEmpty(fieldMap)) {
????????????LOGGER.error("can not insert entity: fieldMap is empty");
????????????return?false;
????????}
????????String sql = "INSERT INTO "?+ entityClass.getSimpleName();
????????StringBuilder columns = new?StringBuilder("(");
????????StringBuilder values = new?StringBuilder("(");
????????for?(String fieldName : fieldMap.keySet()) {
????????????columns.append(fieldName).append(", ");
????????????values.append("?, ");
????????}
????????columns.replace(columns.lastIndexOf(", "), columns.length(), ")");
????????values.replace(values.lastIndexOf(", "), values.length(), ")");
????????sql += columns + " VALUES "?+ values;
????????Object[] params?= fieldMap.values().toArray();
????????return?update(sql, params) == 1;
????}
????/**
?????* 更新實(shí)體
?????*/
????public?static? boolean updateEntity(Class entityClass, long?id, Map fieldMap ) {
????????if?(MapUtils.isEmpty(fieldMap)) {
????????????LOGGER.error("can not update entity: fieldMap is empty");
????????????return?false;
????????}
????????String sql = "UPDATE "?+ entityClass.getSimpleName() + " SET ";
????????StringBuilder columns = new?StringBuilder();
????????for?(String fieldName : fieldMap.keySet()) {
????????????columns.append(fieldName).append(" = ?, ");
????????}
????????sql += columns.substring(0, columns.lastIndexOf(", ")) + " WHERE id = ?";
????????List (2) TransactionProxy 類
TransactionProxy 為事務(wù)切面類, 同樣實(shí)現(xiàn)了Proxy接口, 其 doProxy() 方法就是先判斷代理方法上有沒有 @Transactional 注解, 如果有就加上事務(wù)管理, 沒有就直接執(zhí)行.
public?class?TransactionProxy?implements?Proxy?{
????private?static?final?Logger LOGGER = LoggerFactory.getLogger(TransactionProxy.class);
????@Override
????public?Object doProxy(ProxyChain proxyChain)?throws?Throwable {
????????Object result;
????????Method method = proxyChain.getTargetMethod();
????????//加了@Transactional注解的方法要做事務(wù)處理
????????if?(method.isAnnotationPresent(Transactional.class)) {
????????????try?{
????????????????DatabaseHelper.beginTransaction();
????????????????LOGGER.debug("begin transaction");
????????????????result = proxyChain.doProxyChain();
????????????????DatabaseHelper.commitTransaction();
????????????????LOGGER.debug("commit transaction");
????????????} catch?(Exception e) {
????????????????DatabaseHelper.rollbackTransaction();
????????????????LOGGER.debug("rollback transaction");
????????????????throw?e;
????????????}
????????} else?{
????????????result = proxyChain.doProxyChain();
????????}
????????return?result;
????}
}(3) AopHelper 助手類
在前面的AOP部分我們已經(jīng)知道了 AopHelper 的作用以及實(shí)現(xiàn)邏輯, 事務(wù)代理相比普通代理的差別是, 我們默認(rèn)所有Service對(duì)象都被代理了, 也就是說(shuō)通過(guò)Service的Class對(duì)象, 從Bean容器中得到的都是代理對(duì)象, 我們?cè)趫?zhí)行代理方法時(shí)會(huì)判斷目標(biāo)方法上是否存在 @Transactional 注解, 有就加上事務(wù)管理, 沒有就直接執(zhí)行, 如上面的代碼?
public?interface?IUserService?{
????List getAllUser() ;
????User GetUserInfoById(Integer id);
????boolean?updateUser(int?id, Map fieldMap) ;
}
@Service
public?class?UserService?implements?IUserService?{
????/**
?????* 獲取所有用戶
?????*/
????public?List getAllUser()? {
????????String sql = "SELECT * FROM user";
????????return?DatabaseHelper.queryEntityList(User.class, sql);
????}
????/**
?????* 根據(jù)id獲取用戶信息
?????*/
????public?User GetUserInfoById(Integer id)?{
????????String sql = "SELECT * FROM user WHERE id = ?";
????????return?DatabaseHelper.queryEntity(User.class, sql, id);
????}
????/**
?????* 修改用戶信息
?????*/
????@Transactional
????public?boolean?updateUser(int?id, Map fieldMap) ?{
????????return?DatabaseHelper.updateEntity(User.class, id, fieldMap);
????}
}事務(wù)管理實(shí)例
(1) 業(yè)務(wù)類
public?interface?IUserService?{
????List getAllUser() ;
????User GetUserInfoById(Integer id);
????boolean?updateUser(int?id, Map fieldMap) ;
}
@Service
public?class?UserService?implements?IUserService?{
????/**
?????* 獲取所有用戶
?????*/
????public?List getAllUser()? {
????????String sql = "SELECT * FROM user";
????????return?DatabaseHelper.queryEntityList(User.class, sql);
????}
????/**
?????* 根據(jù)id獲取用戶信息
?????*/
????public?User GetUserInfoById(Integer id)?{
????????String sql = "SELECT * FROM user WHERE id = ?";
????????return?DatabaseHelper.queryEntity(User.class, sql, id);
????}
????/**
?????* 修改用戶信息
?????*/
????@Transactional
????public?boolean?updateUser(int?id, Map fieldMap) ?{
????????return?DatabaseHelper.updateEntity(User.class, id, fieldMap);
????}
}(2) 處理器
@Controller
public?class?UserController {
????@Autowired
????private?IUserService userService;
????/**
?????* 用戶列表
?????*
?????* @return
?????*/
????@RequestMapping(value = "/userList", method = RequestMethod.GET)
????public?View getUserList() {
????????List userList = userService.getAllUser();
????????return?new?View("index.jsp").addModel("userList", userList);
????}
????/**
?????* 用戶詳情
?????*
?????* @param param
?????* @return
?????*/
????@RequestMapping(value = "/userInfo", method = RequestMethod.GET)
????public?Data getUserInfo(Param param) {
????????String?id = (String) param.getParamMap().get("id");
????????User user = userService.GetUserInfoById(Integer.parseInt(id));
????????return?new?Data(user);
????}
????@RequestMapping(value = "/userEdit", method = RequestMethod.GET)
????public?Data editUser(Param param) {
????????String?id = (String) param.getParamMap().get("id");
????????Map<String, Object> fieldMap = new?HashMap<>();
????????fieldMap.put("age", 911);
????????userService.updateUser(Integer.parseInt(id), fieldMap);
????????return?new?Data("Success.");
????}
} (3) JSP頁(yè)面
<%@?page?pageEncoding="UTF-8"?%>
<%@?taglib?prefix="c"?uri="http://java.sun.com/jsp/jstl/core"?%>
<c:set?var="BASE"?value="${pageContext.request.contextPath}"/>
<html>
<head>
????<title>用戶信息title>
head>
<body>
<h1>用戶信息h1>
<table>
????<tr>
????????<th>用戶idth>
????????<th>名稱th>
????????<th>年齡th>
????tr>
????<c:forEach?var="userinfo"?items="${userList}">
????????<tr>
????????????<td>${userinfo.id}td>
????????????<td>${userinfo.name}td>
????????????<td>${userinfo.age}td>
????????????<td>
????????????????<a?href="${BASE}/userInfo?id=${userinfo.id}">詳情a>
????????????????<a?href="${BASE}/userEdit?id=${userinfo.id}">編輯a>
????????????td>
????????tr>
????c:forEach>
table>
body>
html>(4) 結(jié)果
http://localhost:8081/handwritten/userList用戶信息

點(diǎn)擊編輯, 控制臺(tái)打印:
begin?transaction
commit?transaction結(jié)束
到此為止, handwritten-mvc-framwork 框架的所有功能都已實(shí)現(xiàn), 包括Bean容器, IOC, MVC, AOP, 事務(wù)管理, 大家可以多看看源代碼, 思路理順之后一定會(huì)收獲良多.
原文鏈接:csdn.net/litianxiang_kaola/article/details/86647057
