自定义@Service、@Autowired、@Transactional注解类,完成基于注解的IOC容器(Bean对象创建及依赖注入维护)和声明式事务控制

自定义注解

1. 自定义@Service注解

  1. package com.learn.transfer.annotation;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. /**
  7. * 标注Service
  8. * @author lijun
  9. */
  10. @Retention(RetentionPolicy.RUNTIME)
  11. @Target(ElementType.TYPE)
  12. public @interface MyService {
  13. public String value() default "";
  14. }

2. 自定义Autowired

  1. package com.learn.transfer.annotation;
  2. import java.lang.annotation.*;
  3. /**
  4. * 自动注入
  5. * @author lijun
  6. */
  7. @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Documented
  10. public @interface MyAutowired {
  11. boolean value() default true;
  12. }

3. 自定义Transactional

  1. package com.learn.transfer.annotation;
  2. import java.lang.annotation.*;
  3. /**
  4. * @author SCKJ-003
  5. */
  6. @Target({ElementType.TYPE})
  7. @Retention(RetentionPolicy.RUNTIME)
  8. @Documented
  9. public @interface MyTransactional {
  10. String value() default "TransactionManager";
  11. }

controller层、service层、dao层 代码

controller层

  1. package com.learn.transfer.servlet;
  2. import com.learn.transfer.annotation.MyAutowired;
  3. import com.learn.transfer.entity.Result;
  4. import com.learn.transfer.factory.BeanFactory;
  5. import com.learn.transfer.service.TransferService;
  6. import com.learn.transfer.utils.JsonUtils;
  7. import org.springframework.context.support.ClassPathXmlApplicationContext;
  8. import javax.servlet.ServletException;
  9. import javax.servlet.annotation.WebServlet;
  10. import javax.servlet.http.HttpServlet;
  11. import javax.servlet.http.HttpServletRequest;
  12. import javax.servlet.http.HttpServletResponse;
  13. import java.io.IOException;
  14. /**
  15. * @author lijun
  16. */
  17. @WebServlet(name="transferServlet",urlPatterns = "/transferServlet")
  18. public class TransferServlet extends HttpServlet {
  19. private TransferService transferService = (TransferService) BeanFactory.getBean("transferService") ;
  20. @Override
  21. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  22. doPost(req,resp);
  23. }
  24. @Override
  25. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  26. // 设置请求体的字符编码
  27. req.setCharacterEncoding("UTF-8");
  28. String fromCardNo = req.getParameter("fromCardNo");
  29. String toCardNo = req.getParameter("toCardNo");
  30. String moneyStr = req.getParameter("money");
  31. int money = Integer.parseInt(moneyStr);
  32. Result result = new Result();
  33. try {
  34. // 2. 调用service层方法
  35. transferService.transfer(fromCardNo,toCardNo,money);
  36. result.setStatus("200");
  37. } catch (Exception e) {
  38. e.printStackTrace();
  39. result.setStatus("201");
  40. result.setMessage(e.toString());
  41. }
  42. // 响应
  43. resp.setContentType("application/json;charset=utf-8");
  44. resp.getWriter().print(JsonUtils.object2Json(result));
  45. }
  46. }

service接口层和实现层

  1. package com.learn.transfer.service;
  2. /**
  3. * @author 应癫
  4. */
  5. public interface TransferService {
  6. void transfer(String fromCardNo,String toCardNo,int money) throws Exception;
  7. }
  1. package com.learn.transfer.service.impl;
  2. import com.learn.transfer.annotation.MyAutowired;
  3. import com.learn.transfer.annotation.MyService;
  4. import com.learn.transfer.annotation.MyTransactional;
  5. import com.learn.transfer.dao.AccountDao;
  6. import com.learn.transfer.entity.Account;
  7. import com.learn.transfer.service.TransferService;
  8. /**
  9. * @author lijun
  10. */
  11. @MyService("transferService")
  12. @MyTransactional
  13. public class TransferServiceImpl implements TransferService {
  14. /**
  15. * 最佳状态
  16. *
  17. * @Description: 最佳状态
  18. * @Param:
  19. * @Return:
  20. * @Author: lijun
  21. * @Date: 2020/9/11
  22. **/
  23. @MyAutowired
  24. private AccountDao accountDao;
  25. public void setAccountDao(AccountDao accountDao) {
  26. this.accountDao = accountDao;
  27. }
  28. @Override
  29. public void transfer(String fromCardNo, String toCardNo, int money) throws Exception {
  30. try{
  31. Account from = accountDao.queryAccountByCardNo(fromCardNo);
  32. Account to = accountDao.queryAccountByCardNo(toCardNo);
  33. from.setMoney(from.getMoney()-money);
  34. to.setMoney(to.getMoney()+money);
  35. accountDao.updateAccountByCardNo(to);
  36. //测试事务回滚
  37. int c = 1/0;
  38. accountDao.updateAccountByCardNo(from);
  39. }catch (Exception e) {
  40. e.printStackTrace();
  41. // 抛出异常便于上层servlet捕获
  42. throw e;
  43. }
  44. }
  45. }

dao接口层和实现层

  1. package com.learn.transfer.dao;
  2. import com.learn.transfer.entity.Account;
  3. /**
  4. * @author lijun
  5. */
  6. public interface AccountDao {
  7. Account queryAccountByCardNo(String cardNo) throws Exception;
  8. int updateAccountByCardNo(Account account) throws Exception;
  9. void text();
  10. }
  1. package com.learn.transfer.dao.impl;
  2. import com.learn.transfer.annotation.MyAutowired;
  3. import com.learn.transfer.annotation.MyService;
  4. import com.learn.transfer.dao.AccountDao;
  5. import com.learn.transfer.entity.Account;
  6. import com.learn.transfer.utils.ConnectionUtils;
  7. import org.springframework.stereotype.Service;
  8. import java.sql.Connection;
  9. import java.sql.PreparedStatement;
  10. import java.sql.ResultSet;
  11. /**
  12. * @author lijun
  13. */
  14. @MyService("AccountDao")
  15. public class AccountDaoImpl implements AccountDao {
  16. @MyAutowired
  17. private ConnectionUtils connectionUtils;
  18. public void setConnectionUtils(ConnectionUtils connectionUtils) {
  19. this.connectionUtils = connectionUtils;
  20. }
  21. @Override
  22. public Account queryAccountByCardNo(String cardNo) throws Exception {
  23. //从连接池获取连接
  24. // Connection con = DruidUtils.getInstance().getConnection();
  25. Connection con = connectionUtils.getCurrentThreadConn();
  26. String sql = "select * from t_account where cardNo=?";
  27. PreparedStatement preparedStatement = con.prepareStatement(sql);
  28. preparedStatement.setString(1,cardNo);
  29. ResultSet resultSet = preparedStatement.executeQuery();
  30. Account account = new Account();
  31. while(resultSet.next()) {
  32. account.setCardNo(resultSet.getString("cardNo"));
  33. account.setName(resultSet.getString("name"));
  34. account.setMoney(resultSet.getInt("money"));
  35. }
  36. resultSet.close();
  37. preparedStatement.close();
  38. //con.close();
  39. return account;
  40. }
  41. @Override
  42. public int updateAccountByCardNo(Account account) throws Exception {
  43. // 从连接池获取连接
  44. // 改造为:从当前线程当中获取绑定的connection连接
  45. //Connection con = DruidUtils.getInstance().getConnection();
  46. Connection con = connectionUtils.getCurrentThreadConn();
  47. String sql = "update t_account set money=? where cardNo=?";
  48. PreparedStatement preparedStatement = con.prepareStatement(sql);
  49. preparedStatement.setInt(1,account.getMoney());
  50. preparedStatement.setString(2,account.getCardNo());
  51. int i = preparedStatement.executeUpdate();
  52. preparedStatement.close();
  53. //con.close();
  54. return i;
  55. }
  56. @Override
  57. public void text() {
  58. System.out.println(123);
  59. }
  60. }

开发中用到的数据库Utils、动态代理Utils等其他相关类

  1. package com.learn.transfer.utils;
  2. import com.learn.transfer.annotation.MyService;
  3. import java.sql.Connection;
  4. import java.sql.SQLException;
  5. /**
  6. * @author lijun
  7. */
  8. @MyService
  9. public class ConnectionUtils {
  10. /**
  11. * 存储当前线程的连接
  12. *
  13. * @Description: TODO
  14. * @Param:
  15. * @Return:
  16. * @Author: lijun
  17. * @Date: 2020/9/11
  18. **/
  19. private ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
  20. /**
  21. * 从当前线程获取连接
  22. */
  23. public Connection getCurrentThreadConn() throws SQLException {
  24. /**
  25. * 判断当前线程中是否已经绑定连接,如果没有绑定,需要从连接池获取一个连接绑定到当前线程
  26. */
  27. Connection connection = threadLocal.get();
  28. if(connection == null) {
  29. // 从连接池拿连接并绑定到线程
  30. connection = DruidUtils.getInstance().getConnection();
  31. // 绑定到当前线程
  32. threadLocal.set(connection);
  33. }
  34. return connection;
  35. }
  36. }
  37. package com.learn.transfer.utils;
  38. import com.alibaba.druid.pool.DruidDataSource;
  39. /**
  40. * @author lijun
  41. */
  42. public class DruidUtils {
  43. private DruidUtils(){
  44. }
  45. private static DruidDataSource druidDataSource = new DruidDataSource();
  46. static {
  47. druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
  48. druidDataSource.setDbType("com.alibaba.druid.pool.DruidDataSource");
  49. druidDataSource.setUrl("jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxxx?useUnicode=true&characterEncoding=utf8&useSSL=true");
  50. druidDataSource.setUsername("root");
  51. druidDataSource.setPassword("root");
  52. }
  53. public static DruidDataSource getInstance() {
  54. return druidDataSource;
  55. }
  56. }
  57. package com.learn.transfer.utils;
  58. import java.util.List;
  59. import com.fasterxml.jackson.core.JsonProcessingException;
  60. import com.fasterxml.jackson.databind.JavaType;
  61. import com.fasterxml.jackson.databind.ObjectMapper;
  62. /**
  63. * JSON工具类(使用的是jackson实现的)
  64. * @author lijun
  65. */
  66. public class JsonUtils {
  67. private static final ObjectMapper MAPPER = new ObjectMapper();
  68. /**
  69. * 将对象转换成json字符串。
  70. * @param data
  71. * @return
  72. */
  73. public static String object2Json(Object data) {
  74. try {
  75. String string = MAPPER.writeValueAsString(data);
  76. return string;
  77. } catch (JsonProcessingException e) {
  78. e.printStackTrace();
  79. }
  80. return null;
  81. }
  82. /**
  83. * 将json结果集转化为对象
  84. *
  85. * @param jsonData json数据
  86. * @param beanType 对象中的object类型
  87. * @return
  88. */
  89. public static <T> T json2Pojo(String jsonData, Class<T> beanType) {
  90. try {
  91. T t = MAPPER.readValue(jsonData, beanType);
  92. return t;
  93. } catch (Exception e) {
  94. e.printStackTrace();
  95. }
  96. return null;
  97. }
  98. /**
  99. * 将json数据转换成pojo对象list
  100. * @param jsonData
  101. * @param beanType
  102. * @return
  103. */
  104. public static <T>List<T> json2List(String jsonData, Class<T> beanType) {
  105. JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
  106. try {
  107. List<T> list = MAPPER.readValue(jsonData, javaType);
  108. return list;
  109. } catch (Exception e) {
  110. e.printStackTrace();
  111. }
  112. return null;
  113. }
  114. }
  115. package com.learn.transfer.utils;
  116. import com.learn.transfer.annotation.MyAutowired;
  117. import com.learn.transfer.annotation.MyService;
  118. import java.sql.SQLException;
  119. /**
  120. * @author lijun
  121. *
  122. * 事务管理器类:负责手动事务的开启、提交、回滚
  123. */
  124. @MyService
  125. public class TransactionManager {
  126. @MyAutowired
  127. private ConnectionUtils connectionUtils;
  128. public void setConnectionUtils(ConnectionUtils connectionUtils) {
  129. this.connectionUtils = connectionUtils;
  130. }
  131. /*private TransactionManager(){
  132. }
  133. private static TransactionManager transactionManager = new TransactionManager();
  134. public static TransactionManager getInstance() {
  135. return transactionManager;
  136. }*/
  137. /**
  138. * 开启手动事务控制
  139. *
  140. * @Description: TODO
  141. * @Param: []
  142. * @Return: void
  143. * @Author: lijun
  144. * @Date: 2020/9/21
  145. **/
  146. public void beginTransaction() throws SQLException {
  147. connectionUtils.getCurrentThreadConn().setAutoCommit(false);
  148. }
  149. // 提交事务
  150. public void commit() throws SQLException {
  151. connectionUtils.getCurrentThreadConn().commit();
  152. }
  153. // 回滚事务
  154. public void rollback() throws SQLException {
  155. connectionUtils.getCurrentThreadConn().rollback();
  156. }
  157. }

实体类

  1. package com.learn.transfer.entity;
  2. /**
  3. * Account 实体类
  4. * @author lijun
  5. */
  6. public class Account {
  7. private String cardNo;
  8. private String name;
  9. private int money;
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public int getMoney() {
  17. return money;
  18. }
  19. public void setMoney(int money) {
  20. this.money = money;
  21. }
  22. public String getCardNo() { return cardNo; }
  23. public void setCardNo(String cardNo) { this.cardNo = cardNo;}
  24. }
  25. package com.learn.transfer.entity;
  26. /**
  27. * Result 实体类
  28. * @author lijun
  29. */
  30. public class Result{
  31. private String status;
  32. private String message;
  33. public String getStatus() {
  34. return status;
  35. }
  36. public void setStatus(String status) {
  37. this.status = status;
  38. }
  39. public String getMessage() {
  40. return message;
  41. }
  42. public void setMessage(String message) {
  43. this.message = message;
  44. }
  45. }

注解解析类BeanFactory

  1. package com.learn.transfer.factory;
  2. import com.alibaba.druid.util.StringUtils;
  3. import com.learn.transfer.annotation.MyAutowired;
  4. import com.learn.transfer.annotation.MyService;
  5. import com.learn.transfer.annotation.MyTransactional;
  6. import org.reflections.Reflections;
  7. import java.lang.reflect.Field;
  8. import java.lang.reflect.InvocationTargetException;
  9. import java.lang.reflect.Method;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. import java.util.Set;
  13. /**
  14. * @ClassName BeanFactory
  15. * @Description TODO
  16. * @Author lijun
  17. * @Date 2020/9/29 10:21
  18. */
  19. public class BeanFactory {
  20. // 存储对象
  21. private static Map<String,Object> map = new HashMap<>();
  22. static{
  23. try{
  24. //扫描包,分析需实例化的对象列表(service和事务管理器),通过反射技术实例化对象并且存储待用(map集合)
  25. //扫描获取反射对象集合
  26. Reflections f = new Reflections("com.learn.transfer");
  27. //获取注解为service的集合
  28. Set<Class<?>> set = f.getTypesAnnotatedWith(MyService.class);
  29. for (Class<?> c : set) {
  30. // 通过反射技术实例化对象
  31. Object bean = c.newInstance();
  32. MyService annotation = c.getAnnotation(MyService.class);
  33. //对象ID在service注解有value时用value,没有时用类名
  34. if(StringUtils.isEmpty(annotation.value())){
  35. //由于getName获取的是全限定类名,所以要分割去掉前面包名部分
  36. String[] names = c.getName().split("\\.");
  37. map.put(names[names.length-1], bean);
  38. }else{
  39. map.put(annotation.value(), bean);
  40. }
  41. }
  42. // 实例化完成之后维护对象的依赖关系,检查哪些对象需要传值进入,根据它的配置,我们传入相应的值
  43. for(Map.Entry<String, Object> a:map.entrySet()){
  44. Object o = a.getValue();
  45. Class c = o.getClass();
  46. //获取属性集合
  47. Field[] fields = c.getDeclaredFields();
  48. //遍历属性,若持有Autowired注解则注入
  49. for (Field field : fields) {
  50. if (field.isAnnotationPresent(MyAutowired.class)
  51. &&field.getAnnotation(MyAutowired.class).value()) {
  52. String[] names = field.getType().getName().split("\\.");
  53. String name = names[names.length-1];
  54. Method[] methods = c.getMethods();
  55. for (int j = 0; j < methods.length; j++) {
  56. Method method = methods[j];
  57. // 该方法就是 setAccountDao(AccountDao accountDao)
  58. if(method.getName().equalsIgnoreCase("set" + name)) {
  59. method.invoke(o,map.get(name));
  60. }
  61. }
  62. }
  63. }
  64. //判断对象类是否持有Transactional注解,若有则修改对象为代理对象
  65. if(c.isAnnotationPresent(MyTransactional.class)){
  66. //获取代理工厂
  67. ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
  68. //判断对象是否实现接口
  69. //获取类c实现的所有接口
  70. Class[] face = c.getInterfaces();
  71. if(face!=null&&face.length>0){
  72. //实现使用JDK
  73. o = proxyFactory.getJdkProxy(o);
  74. }else{
  75. //没实现使用CGLIB
  76. o = proxyFactory.getCglibProxy(o);
  77. }
  78. }
  79. // 把处理之后的object重新放到map中
  80. map.put(a.getKey(),o);
  81. }
  82. } catch (IllegalAccessException e) {
  83. e.printStackTrace();
  84. } catch (InstantiationException e) {
  85. e.printStackTrace();
  86. } catch (InvocationTargetException e) {
  87. e.printStackTrace();
  88. }
  89. }
  90. /**
  91. * 对外提供获取实例对象的接口(根据id获取)
  92. *
  93. * @Description: TODO
  94. * @Param: [id]
  95. * @Return: java.lang.Object
  96. * @Author: lijun
  97. * @Date: 2020/9/29
  98. **/
  99. public static Object getBean(String id) {
  100. return map.get(id);
  101. }
  102. }

代理工厂

  1. package com.learn.transfer.factory;
  2. import com.learn.transfer.annotation.MyAutowired;
  3. import com.learn.transfer.annotation.MyService;
  4. import com.learn.transfer.utils.TransactionManager;
  5. import net.sf.cglib.proxy.Enhancer;
  6. import net.sf.cglib.proxy.MethodInterceptor;
  7. import net.sf.cglib.proxy.MethodProxy;
  8. import java.lang.reflect.InvocationHandler;
  9. import java.lang.reflect.Method;
  10. import java.lang.reflect.Proxy;
  11. /**
  12. * @ClassName ProxyFactory
  13. * @Description TODO
  14. * @Author lijun
  15. * @Date 2020/9/29 10:21
  16. */
  17. @MyService("proxyFactory")
  18. public class ProxyFactory {
  19. @MyAutowired
  20. private TransactionManager transactionManager;
  21. public void setTransactionManager(TransactionManager transactionManager) {
  22. this.transactionManager = transactionManager;
  23. }
  24. /**
  25. * Jdk动态代理
  26. *
  27. * @Description: TODO
  28. * @Param: [obj]
  29. * @Return: java.lang.Object
  30. * @Author: lijun
  31. * @Date: 2020/9/29
  32. **/
  33. public Object getJdkProxy(Object obj) {
  34. // 获取代理对象
  35. return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
  36. new InvocationHandler() {
  37. @Override
  38. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  39. Object result = null;
  40. try{
  41. // 开启事务(关闭事务的自动提交)
  42. transactionManager.beginTransaction();
  43. result = method.invoke(obj,args);
  44. // 提交事务
  45. transactionManager.commit();
  46. }catch (Exception e) {
  47. e.printStackTrace();
  48. // 回滚事务
  49. transactionManager.rollback();
  50. // 抛出异常便于上层servlet捕获
  51. throw e;
  52. }
  53. return result;
  54. }
  55. });
  56. }
  57. /**
  58. * 使用cglib动态代理生成代理对象
  59. *
  60. * @Description: TODO
  61. * @Param: [obj] 委托对象
  62. * @Return: java.lang.Object
  63. * @Author: lijun
  64. * @Date: 2020/9/29
  65. **/
  66. public Object getCglibProxy(Object obj) {
  67. return Enhancer.create(obj.getClass(), new MethodInterceptor() {
  68. @Override
  69. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  70. Object result = null;
  71. try{
  72. // 开启事务(关闭事务的自动提交)
  73. transactionManager.beginTransaction();
  74. result = method.invoke(obj,objects);
  75. // 提交事务
  76. transactionManager.commit();
  77. }catch (Exception e) {
  78. e.printStackTrace();
  79. // 回滚事务
  80. transactionManager.rollback();
  81. // 抛出异常便于上层servlet捕获
  82. throw e;
  83. }
  84. return result;
  85. }
  86. });
  87. }
  88. }

时序图

自定义@Service、@Autowired、@Transactional注解类,完成基于注解的IOC容器(Bean对象创建及依赖注入维护)和声明式事务控制 - 图2