自定义@Service注解java
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface CustomService { String value() default ""; }
自定义@Autowired注解mysql
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface CustomAutowired { }
自定义@Transactional注解spring
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface CustomTransactional { }
接下来,咱们看一下controller层、service层、dao层 代码sql
- controller层
@WebServlet(name="transferServlet",urlPatterns = "/transferServlet") public class TransferServlet extends HttpServlet { TransferService 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 { CustomApplicationContext customApplicationContext = new CustomApplicationContext("com.zhu.yuandi"); transferService = (TransferService) customApplicationContext.getBean("TransferService",customApplicationContext); // 设置请求体的字符编码 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 { //调用service层方法 transferService.transfer(fromCardNo,toCardNo,money); result.setStatus("200"); } catch (Exception e) { e.printStackTrace(); result.setStatus("201"); result.setMessage(e.toString()); } // 响应 resp.setContentType("application/json;charset=utf-8"); resp.getWriter().print(JsonUtils.object2Json(result)); } }
- service层
public interface TransferService { void transfer(String fromCardNo,String toCardNo,int money) throws Exception; } @CustomService(value = "transferService") @CustomTransactional public class TransferServiceImpl implements TransferService { @CustomAutowired private AccountDao accountDao; @Override public void transfer(String fromCardNo, String toCardNo, int money) throws Exception { 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); } }
- dao层
public interface AccountDao { Account queryAccountByCardNo(String cardNo) throws Exception; int updateAccountByCardNo(Account account) throws Exception; } @CustomService public class JdbcAccountDaoImpl implements AccountDao { @CustomAutowired private ConnectionUtils connectionUtils; @Override public Account queryAccountByCardNo(String cardNo) throws Exception { 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(); return account; } @Override public int updateAccountByCardNo(Account account) throws Exception { 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(); return i; } }
开发中用到的数据库Utils、动态代理Utils等其余相关类数据库
@CustomService public class ConnectionUtils { private ThreadLocal<Connection> threadLocal = new ThreadLocal<>(); // 存储当前线程的链接 /** * 从当前线程获取链接 */ public Connection getCurrentThreadConn() throws SQLException { /** * 判断当前线程中是否已经绑定链接,若是没有绑定,须要从链接池获取一个链接绑定到当前线程 */ Connection connection = threadLocal.get(); if(connection == null) { // 从链接池拿链接并绑定到线程 connection = DruidUtils.getInstance().getConnection(); // 绑定到当前线程 threadLocal.set(connection); } return connection; } } public class DruidUtils { private DruidUtils(){ } private static DruidDataSource druidDataSource = new DruidDataSource(); static { druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); druidDataSource.setUrl("jdbc:mysql://localhost:3306/bank?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Hongkong"); druidDataSource.setUsername("root"); druidDataSource.setPassword("root"); } public static DruidDataSource getInstance() { return druidDataSource; } } @CustomService public class ProxyFactory { @CustomAutowired private TransactionManager transactionManager; /** * Jdk动态代理 * @param obj 委托对象 * @return 代理对象 */ public Object getJdkProxy(Object obj) { // 获取代理对象 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{ // 开启事务(关闭事务的自动提交) transactionManager.beginTransaction(); result = method.invoke(obj,args); // 提交事务 transactionManager.commit(); }catch (Exception e) { e.printStackTrace(); // 回滚事务 transactionManager.rollback(); // 抛出异常便于上层servlet捕获 throw e; } return result; } }); } } @CustomService public class TransactionManager { @CustomAutowired private ConnectionUtils connectionUtils; // 开启手动事务控制 public void beginTransaction() throws SQLException { connectionUtils.getCurrentThreadConn().setAutoCommit(false); } // 提交事务 public void commit() throws SQLException { connectionUtils.getCurrentThreadConn().commit(); } // 回滚事务 public void rollback() throws SQLException { connectionUtils.getCurrentThreadConn().rollback(); } } 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 + '}'; } }
注解解析类json
public class CustomApplicationContext { //包名 private String packageName; private ConcurrentHashMap<String, Object> beans = new ConcurrentHashMap<>(); public CustomApplicationContext(String packageName) { this.packageName = packageName; initBeans(); } private void initBeans() { List<Class> classList = getClasses(packageName); findClassIsAddedCostomAnnotation(classList); } private List<Class> getClasses(String packageName) { List<Class> classList = new ArrayList<>(); String packageDirName = packageName.replace(".", "/"); Enumeration<URL> dirs; try { dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); while (dirs.hasMoreElements()) { URL url = dirs.nextElement(); String protocol = url.getProtocol(); if (protocol.equals("file")) { String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); findAndAddClassesInPackageByFile(packageName, filePath, classList); } } } catch (Exception e) { e.printStackTrace(); } return classList; } private void findAndAddClassesInPackageByFile(String packageName, String filePath, List<Class> classList) { File dir = new File(filePath); //选出文件夹下面全部的文件 File[] files = dir.listFiles(new FileFilter() { public boolean accept(File file) { return (file.isDirectory() || file.getName().endsWith(".class")); } }); for (File file : files) { if (file.isDirectory()) { findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), classList); } else { String className = file.getName().substring(0, file.getName().length() - 6); try { classList.add(Class.forName(packageName + "." + className)); } catch (Exception e) { e.printStackTrace(); } } } } private void findClassIsAddedCostomAnnotation(List<Class> classList) { try{ for (Class aClass : classList) { classToObjectIntoBeans(aClass, classList); } }catch (Exception e){ e.printStackTrace(); } } private void classToObjectIntoBeans(Class aClass, List<Class> classList) { Object obj = null; try{ if(aClass.isInterface()){ for(Class implClass : classList) { if (implClass.isInterface()) { continue; } Class fieldClassCopy = implClass.getClassLoader().loadClass(aClass.getName()); if (fieldClassCopy.isAssignableFrom(implClass)) { Constructor[] constructors = implClass.getConstructors(); for(Constructor constructor : constructors){ int parameterCount = constructor.getParameterCount(); if(parameterCount==0){ obj = constructor.newInstance(); } } break; } } } else { Constructor[] constructors = aClass.getConstructors(); for(Constructor constructor : constructors){ int parameterCount = constructor.getParameterCount(); if(parameterCount==0){ obj = constructor.newInstance(); } } } if (obj != null) { beans.put(aClass.getSimpleName(), obj); } }catch (Exception e){ e.printStackTrace(); } } public Object getBean(String beanName,CustomApplicationContext customApplicationContext) { Object beanObject = beans.get(beanName); try{ referenceBindObject(beanObject); }catch (Exception e){ e.printStackTrace(); } Class aClass = beanObject.getClass(); Annotation annotation = aClass.getAnnotation(CustomTransactional.class); if (annotation != null) { ProxyFactory proxyFactory = (ProxyFactory) customApplicationContext.getBean("ProxyFactory", customApplicationContext); beanObject = proxyFactory.getJdkProxy(beanObject); } return beanObject; } private Object referenceBindObject(Object beanObject) { Class beanClass = beanObject.getClass(); Field[] declaredFields = beanClass.getDeclaredFields(); try { for (Field field : declaredFields) { if (!field.isAccessible()) { field.setAccessible(true); } CustomAutowired filedAnnotation = field.getAnnotation(CustomAutowired.class); if (filedAnnotation == null) { System.out.println(beanClass.getName() + "类中的" + field.getName() + "字段,该字段上没有加注解"); break; } Class fieldClass = field.getType(); String classSimpleName = fieldClass.getSimpleName(); Object fieldObject = beans.get(classSimpleName); Object object = referenceBindObject(fieldObject); field.set(beanObject, object); } } catch (Exception e) { e.printStackTrace(); } return beanObject; } }
- 以上,咱们完成了自定义注解,实现了spring ioc容器功能;加上自定义事务注解,实现了事务功能。
- 若是须要视频讲解,私聊我,本人录制了运行效果展现和代码讲解视频。