自定义@Service、@Autowired、@Transactional注解类,完成基于注解的IOC容器(Bean对象创建及依赖注入维护)和声明式事务控制
自定义注解
1. 自定义@Service注解
package com.learn.transfer.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/*** 标注Service* @author lijun*/@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface MyService {public String value() default "";}
2. 自定义Autowired
package com.learn.transfer.annotation;import java.lang.annotation.*;/*** 自动注入* @author lijun*/@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MyAutowired {boolean value() default true;}
3. 自定义Transactional
package com.learn.transfer.annotation;import java.lang.annotation.*;/*** @author SCKJ-003*/@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MyTransactional {String value() default "TransactionManager";}
controller层、service层、dao层 代码
controller层
package com.learn.transfer.servlet;import com.learn.transfer.annotation.MyAutowired;import com.learn.transfer.entity.Result;import com.learn.transfer.factory.BeanFactory;import com.learn.transfer.service.TransferService;import com.learn.transfer.utils.JsonUtils;import org.springframework.context.support.ClassPathXmlApplicationContext;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;/*** @author lijun*/@WebServlet(name="transferServlet",urlPatterns = "/transferServlet")public class TransferServlet extends HttpServlet {private TransferService transferService = (TransferService) BeanFactory.getBean("transferService") ;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 设置请求体的字符编码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. 调用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接口层和实现层
package com.learn.transfer.service;/*** @author 应癫*/public interface TransferService {void transfer(String fromCardNo,String toCardNo,int money) throws Exception;}
package com.learn.transfer.service.impl;import com.learn.transfer.annotation.MyAutowired;import com.learn.transfer.annotation.MyService;import com.learn.transfer.annotation.MyTransactional;import com.learn.transfer.dao.AccountDao;import com.learn.transfer.entity.Account;import com.learn.transfer.service.TransferService;/*** @author lijun*/@MyService("transferService")@MyTransactionalpublic class TransferServiceImpl implements TransferService {/*** 最佳状态** @Description: 最佳状态* @Param:* @Return:* @Author: lijun* @Date: 2020/9/11**/@MyAutowiredprivate AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}@Overridepublic void transfer(String fromCardNo, String toCardNo, int money) throws Exception {try{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);}catch (Exception e) {e.printStackTrace();// 抛出异常便于上层servlet捕获throw e;}}}
dao接口层和实现层
package com.learn.transfer.dao;import com.learn.transfer.entity.Account;/*** @author lijun*/public interface AccountDao {Account queryAccountByCardNo(String cardNo) throws Exception;int updateAccountByCardNo(Account account) throws Exception;void text();}
package com.learn.transfer.dao.impl;import com.learn.transfer.annotation.MyAutowired;import com.learn.transfer.annotation.MyService;import com.learn.transfer.dao.AccountDao;import com.learn.transfer.entity.Account;import com.learn.transfer.utils.ConnectionUtils;import org.springframework.stereotype.Service;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;/*** @author lijun*/@MyService("AccountDao")public class AccountDaoImpl implements AccountDao {@MyAutowiredprivate ConnectionUtils connectionUtils;public void setConnectionUtils(ConnectionUtils connectionUtils) {this.connectionUtils = connectionUtils;}@Overridepublic Account queryAccountByCardNo(String cardNo) throws Exception {//从连接池获取连接// Connection con = DruidUtils.getInstance().getConnection();Connection con = connectionUtils.getCurrentThreadConn();String sql = "select * from t_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();return account;}@Overridepublic int updateAccountByCardNo(Account account) throws Exception {// 从连接池获取连接// 改造为:从当前线程当中获取绑定的connection连接//Connection con = DruidUtils.getInstance().getConnection();Connection con = connectionUtils.getCurrentThreadConn();String sql = "update t_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;}@Overridepublic void text() {System.out.println(123);}}
开发中用到的数据库Utils、动态代理Utils等其他相关类
package com.learn.transfer.utils;import com.learn.transfer.annotation.MyService;import java.sql.Connection;import java.sql.SQLException;/*** @author lijun*/@MyServicepublic class ConnectionUtils {/*** 存储当前线程的连接** @Description: TODO* @Param:* @Return:* @Author: lijun* @Date: 2020/9/11**/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;}}package com.learn.transfer.utils;import com.alibaba.druid.pool.DruidDataSource;/*** @author lijun*/public class DruidUtils {private DruidUtils(){}private static DruidDataSource druidDataSource = new DruidDataSource();static {druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");druidDataSource.setDbType("com.alibaba.druid.pool.DruidDataSource");druidDataSource.setUrl("jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxxx?useUnicode=true&characterEncoding=utf8&useSSL=true");druidDataSource.setUsername("root");druidDataSource.setPassword("root");}public static DruidDataSource getInstance() {return druidDataSource;}}package com.learn.transfer.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实现的)* @author lijun*/public class JsonUtils {private static final ObjectMapper MAPPER = new ObjectMapper();/*** 将对象转换成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结果集转化为对象** @param jsonData json数据* @param beanType 对象中的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数据转换成pojo对象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;}}package com.learn.transfer.utils;import com.learn.transfer.annotation.MyAutowired;import com.learn.transfer.annotation.MyService;import java.sql.SQLException;/*** @author lijun** 事务管理器类:负责手动事务的开启、提交、回滚*/@MyServicepublic class TransactionManager {@MyAutowiredprivate ConnectionUtils connectionUtils;public void setConnectionUtils(ConnectionUtils connectionUtils) {this.connectionUtils = connectionUtils;}/*private TransactionManager(){}private static TransactionManager transactionManager = new TransactionManager();public static TransactionManager getInstance() {return transactionManager;}*//*** 开启手动事务控制** @Description: TODO* @Param: []* @Return: void* @Author: lijun* @Date: 2020/9/21**/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();}}
实体类
package com.learn.transfer.entity;/*** Account 实体类* @author lijun*/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;}}package com.learn.transfer.entity;/*** Result 实体类* @author lijun*/public class Result{private String status;private String message;public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}}
注解解析类BeanFactory
package com.learn.transfer.factory;import com.alibaba.druid.util.StringUtils;import com.learn.transfer.annotation.MyAutowired;import com.learn.transfer.annotation.MyService;import com.learn.transfer.annotation.MyTransactional;import org.reflections.Reflections;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import java.util.Set;/*** @ClassName BeanFactory* @Description TODO* @Author lijun* @Date 2020/9/29 10:21*/public class BeanFactory {// 存储对象private static Map<String,Object> map = new HashMap<>();static{try{//扫描包,分析需实例化的对象列表(service和事务管理器),通过反射技术实例化对象并且存储待用(map集合)//扫描获取反射对象集合Reflections f = new Reflections("com.learn.transfer");//获取注解为service的集合Set<Class<?>> set = f.getTypesAnnotatedWith(MyService.class);for (Class<?> c : set) {// 通过反射技术实例化对象Object bean = c.newInstance();MyService annotation = c.getAnnotation(MyService.class);//对象ID在service注解有value时用value,没有时用类名if(StringUtils.isEmpty(annotation.value())){//由于getName获取的是全限定类名,所以要分割去掉前面包名部分String[] names = c.getName().split("\\.");map.put(names[names.length-1], bean);}else{map.put(annotation.value(), bean);}}// 实例化完成之后维护对象的依赖关系,检查哪些对象需要传值进入,根据它的配置,我们传入相应的值for(Map.Entry<String, Object> a:map.entrySet()){Object o = a.getValue();Class c = o.getClass();//获取属性集合Field[] fields = c.getDeclaredFields();//遍历属性,若持有Autowired注解则注入for (Field field : fields) {if (field.isAnnotationPresent(MyAutowired.class)&&field.getAnnotation(MyAutowired.class).value()) {String[] names = field.getType().getName().split("\\.");String name = names[names.length-1];Method[] methods = c.getMethods();for (int j = 0; j < methods.length; j++) {Method method = methods[j];// 该方法就是 setAccountDao(AccountDao accountDao)if(method.getName().equalsIgnoreCase("set" + name)) {method.invoke(o,map.get(name));}}}}//判断对象类是否持有Transactional注解,若有则修改对象为代理对象if(c.isAnnotationPresent(MyTransactional.class)){//获取代理工厂ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");//判断对象是否实现接口//获取类c实现的所有接口Class[] face = c.getInterfaces();if(face!=null&&face.length>0){//实现使用JDKo = proxyFactory.getJdkProxy(o);}else{//没实现使用CGLIBo = proxyFactory.getCglibProxy(o);}}// 把处理之后的object重新放到map中map.put(a.getKey(),o);}} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}/*** 对外提供获取实例对象的接口(根据id获取)** @Description: TODO* @Param: [id]* @Return: java.lang.Object* @Author: lijun* @Date: 2020/9/29**/public static Object getBean(String id) {return map.get(id);}}
代理工厂
package com.learn.transfer.factory;import com.learn.transfer.annotation.MyAutowired;import com.learn.transfer.annotation.MyService;import com.learn.transfer.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;/*** @ClassName ProxyFactory* @Description TODO* @Author lijun* @Date 2020/9/29 10:21*/@MyService("proxyFactory")public class ProxyFactory {@MyAutowiredprivate TransactionManager transactionManager;public void setTransactionManager(TransactionManager transactionManager) {this.transactionManager = transactionManager;}/*** Jdk动态代理** @Description: TODO* @Param: [obj]* @Return: java.lang.Object* @Author: lijun* @Date: 2020/9/29**/public Object getJdkProxy(Object obj) {// 获取代理对象return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic 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;}});}/*** 使用cglib动态代理生成代理对象** @Description: TODO* @Param: [obj] 委托对象* @Return: java.lang.Object* @Author: lijun* @Date: 2020/9/29**/public Object getCglibProxy(Object obj) {return Enhancer.create(obj.getClass(), new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {Object result = null;try{// 开启事务(关闭事务的自动提交)transactionManager.beginTransaction();result = method.invoke(obj,objects);// 提交事务transactionManager.commit();}catch (Exception e) {e.printStackTrace();// 回滚事务transactionManager.rollback();// 抛出异常便于上层servlet捕获throw e;}return result;}});}}

