手写@Service、@Autowired、@Transactional注解,实现spring ioc和spring事务
自定义@Service注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomService {
String value() default "";
}
自定义@Autowired注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAutowired {
}
自定义@Transactional注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomTransactional {
}
接下来,我们看一下controller层、service层、dao层 代码
- 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 +
'}';
}
}
注解解析类
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容器功能;加上自定义事务注解,实现了事务功能。
- 如果需要视频讲解,私聊我,本人录制了运行效果展示和代码讲解视频。
手写@Service、@Autowired、@Transactional注解,实现spring ioc和spring事务的更多相关文章
- spring揭密学习笔记(3)-spring ioc容器:Spring的IoC容器之BeanFactory
1. Spring的IoC容器和IoC Service Provider的关系 Spring的IoC容器和IoC Service Provider所提供的服务之间存在一定的交集,二者的关系如图4-1所 ...
- Spring IOC和Spring AOP的实现原理(源码主线流程)
写在前面 正本文参考了<spring技术内幕>和spring 4.0.5源码.本文只描述原理流程的主线部分,其他比如验证,缓存什么可以具体参考源码理解. Spring IOC 一.容器初始 ...
- 【Spring IoC】Spring Bean(三)
一.Spring Bean的定义 被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的.bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象. ...
- Spring Boot中Service用@Transactional 注解
一般来说function2和function1用的是同一个Transaction. 这个取决于@Transactional 的 propagation设置(事务的传播性) 默认的是 1 @Transa ...
- spring ioc 原理 spring aop原理
大家一直都说spring的IOC如何如何的强大,其实我倒觉得不是IOC如何的强大,说白了IOC其实也非常的简单.我们先从IOC说起,这个概念其实是从我们平常new一个对象的对立面来说的,我们平常使用对 ...
- Spring - IoC(1): Spring 容器
BeanFactory & ApplicationContext org.springframework.beans.factory.BeanFactory 是最基本的 Spring 容器接口 ...
- spring IOC(Spring 生命周期,先1.构造方式,2,初始化方法,3,目标方法,4,销毁方法)
- Spring Boot 中使用 @Transactional 注解配置事务管理
事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功能支持.Spring 事务管理分为编程式和声明式的两种方式.编程式事务指的是通过编码方式实现事务:声明式事务基于 AOP ...
- Spring对于事务的控制@Transactional注解详解
引用自:https://blog.csdn.net/fanxb92/article/details/81296005 先简单介绍一下Spring事务的传播行为: 所谓事务的传播行为是指,如果在开始当前 ...
随机推荐
- springboot 使用DruidDataSource 数据源
一.添加依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</art ...
- ios 富文本 加颜色 删除线
UILabel *valueL = [JAppViewTools getLabel:CGRectMake(JFWidth(15), CGRectGetMaxY(proName.frame)+JFWid ...
- alpine 容器优化
摘要:alpine容器一直是使用得比较多的,而且也是官方推荐使用的.但是官方的容器会有一些不方便的地方,比如安装软件, 时区不同等. 所以本文旨在完成一个alpine容器通用模板作为记录 # 导入 ...
- 职场老鸟,一文教你如何正确入门Python爬虫!
爬虫现在的火热程度我就不说了,先说一下这门技术能干什么事儿,主要为以下三方面: 1.爬取数据,进行市场调研和商业分析 爬取知乎.豆瓣等网站的优质话题内容:抓取房产网站买卖信息,分析房价变化趋势.做不同 ...
- 006_go语言中的if else条件语句
代码演示 package main import "fmt" func main() { if 7%2 == 0 { fmt.Println("7 is even&quo ...
- JDK11.0.7下载及安装详细教程(win10)
0.背景知识 JRE: Java Runtime Environment JDK:Java Development Kit JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库. ...
- LinuX操作系统基础------>初始并安装系统
b了解LinuX操作系统的来历和发展史 掌握虚拟机(Vbox)的安装方法 掌握CentOS6.5的安装方法 操作系统: 操作系统简称OS ,是管理计算机硬件与软件资源的计算机程序,同时也是计算机系统的 ...
- SEO(Search Engine Optimization)优化
SEO(Search Engine Optimization)汉议为搜索引擎优化,是一种利用搜索引擎的规则提高网站在有关搜索引擎内自然排名的方式. SEO的目的是对网站进行深度的优化,从而帮助网站获取 ...
- Linux查询版本、查询端口
lsb_release -a 查看当前Linux系统版本 netstat 检查端口 netstat 是一个命令行工具,可以提供有关网络连接的信息.要列出正在侦听的所有 TCP 或 UDP 端口,包括使 ...
- CentOS7(Linux)源码安装MySQL5.7.X
介绍 软件应用最重要的就是数据库了,可是还有小伙伴不会在Linux上安装MySQL数据库,今天就来讲讲如何在CentOS7环境使用源码进行安装MySQL5.7.X. MySQL官网下载链接:https ...