整体架构
Spring框架可在任何类型的部署平台上为基于Java的企业应用程序提供全面的编程和配置模型。
Spring的一个关键元素是在应用程序级别的基础框架支持:Spring专注于企业应用程序的“探索”,以便于团队可以专注于应用程序级别的业务逻辑,而不必处理特定的部署环境问题。
Spring可以理解为框架粘合剂,大部分的框架都是不可以相互作用的。Spring提供了这样一个平台,框架只需要向Spring靠拢即可。最终结果就是基于Spring实现了不同框架技术的整合。而且Spring提供了对各大框架的支持,我们可以更加方便的使用。
Spring的核心是IOC和AOP功能,基于IOC实现对象的依赖和管理,基于AOP实现了事务的控制和管理。
简化开发、功能解耦
通过IOC容器,那么对象直接的依赖关系交给Spring管理与控制,而且基于面向接口编程可以使得代码解耦,改变实现类不需要修改引用。
AOP编码支持
通过AOP功能,可以面向切面编程,传统的基于OOP实现的功能可以通过AOP轻松搞定。
声明式事务
@Transactional
事务注解可以帮助我们实现事务控制与管理,而不需要手动进行事务管理。是的事务与代码解耦,声明式事务可以非常灵活的配置,提供开发的效率和质量。
方便程序测试
Spring提供了对测试的支持,可以非常方便的构建测试。
方便集成框架
前面说过Spring其实是一个粘合剂,可以非常轻松的将各种框架整合到项目中,而且还提供了更加简便的操作方式。
降低JavaEE API的使用难度
Spring内部其实对很多的JavaEE API进行了封装,是的我们面的JavaEE编程的时候更加方便。如JDBC、JavaMail等功能。
IOC:Inversion of Control(控制反转),这是一种技术思想。主要是解决Java开发领域的对象创建和管理问题。
传统对象管理(手动创建对象和依赖)
IoC管理(由IoC创建并管理对象)
IoC主要解决对象之间的耦合问题,我们不关心对象的创建和如何依赖,只需要在使用的地方@Autowired
注入即可。IoC会帮助我们注入和管理所需要的Bean
IoC和DI的关系
DI:Dependancy Injection(依赖注入)
IoC是控制反转,DI是依赖注入。它们共同完成了对象管理这一件事情。
AOP:Aspect oriented Programming面向切面编程
AOP其实是OOP思想的延续和扩展。OOP是一种垂直结构,AOP是一种横向结构。
OOP的体系开发模式
AOP切面编程
如何理解切面
在2.2.3部分,我们已经对IoC和AOP思想有了大致的了解,但是这都是基于概念和思想上的。下面我们通过一个《银行转账》的基础案例分析其中的问题,然后基于IoC和AOP思想慢慢的改造解决痛点问题并加深我们的理解和认识。
开发过程:转账操作可以写html页面发起请求,也可以使用功能http模拟请求。
银行转账:
数据库SQL准备
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for account
-- ----------------------------
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (`cardNo` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`name` varchar(5) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`money` int(11) NULL DEFAULT 0
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of account
-- ----------------------------
INSERT INTO `account` VALUES ('1006029621011001', '张三', 100000);
INSERT INTO `account` VALUES ('2006029621011000', '李四', 100000);SET FOREIGN_KEY_CHECKS = 1;
Maven依赖
<dependencies><!-- 单元测试Junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><!-- mysql数据库驱动包 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.35</version></dependency><!--druid连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.21</version></dependency><!-- servlet --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><!-- jackson依赖 --><dependency><groupId>com.</groupId><artifactId>jackson-databind</artifactId><version>2.9.6</version></dependency><!--dom4j依赖--><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency><!--xpath表达式依赖--><dependency><groupId>jaxen</groupId><artifactId>jaxen</artifactId><version>1.1.6</version></dependency><!--引入cglib依赖包--><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.1_2</version></dependency>
</dependencies>
// 数据库实体映射
public class Account {private String cardNo;private String name;private int money;// getter setter@Overridepublic String toString() {return "Account{" +"cardNo='" + cardNo + ''' +", name='" + name + ''' +", money=" + money +'}';}
}
// 处理结果响应
public class Result {private String status;private String message;// getter setter@Overridepublic String toString() {return "Result{" +"status='" + status + ''' +", message='" + message + ''' +'}';}
}
// 封装数据库连接池
public class DruidUtils {private DruidUtils() {}private static DruidDataSource druidDataSource = new DruidDataSource();static {druidDataSource.setDriverClassName(sql.jdbc.Driver");druidDataSource.setUrl("jdbc:mysql://localhost:3306/lagou_spring");druidDataSource.setUsername("root");druidDataSource.setPassword("root");}public static DruidDataSource getInstance() {return druidDataSource;}
}
@WebServlet(name = "transferServlet", urlPatterns = "/transferServlet")
public class TransferServlet extends HttpServlet {// 实例化service层对象private TransferService transferService = new TransferServiceImpl();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponseresp) throws ServletException, IOException {// 设置请求体的字符编码,避免编码错误req.setCharacterEncoding("UTF-8");String fromCardNo = Parameter("fromCardNo");String toCardNo = Parameter("toCardNo");String moneyStr = Parameter("money");int money = Integer.parseInt(moneyStr);Result result = new Result();try {// 2. 调用transferService实现转账ansfer(fromCardNo, toCardNo, money);result.setStatus("200");} catch (Exception e) {e.printStackTrace();result.setStatus("201");result.String());}// 响应resp.setContentType("application/json;charset=utf-8");Writer().print(JsonUtils.object2Json(result));}
}
public interface TransferService {void transfer(String fromCardNo, String toCardNo, int money) throws Exception;
}
public class TransferServiceImpl implements TransferService {// 实例化Jdbc操作数据库对象private AccountDao accountDao = new JdbcAccountDaoImpl();@Overridepublic void transfer(String fromCardNo, String toCardNo, int money) throws Exception {Account from = accountDao.queryAccountByCardNo(fromCardNo);Account to = accountDao.queryAccountByCardNo(toCardNo);from.Money() - money);to.Money() + money);accountDao.updateAccountByCardNo(to);// 模拟转账异常,现在暂时不开启,记住后面需要开启模拟异常// int c = 1 / 0;accountDao.updateAccountByCardNo(from);}
}
public interface AccountDao {Account queryAccountByCardNo(String cardNo) throws Exception;int updateAccountByCardNo(Account account) throws Exception;
}
public class JdbcAccountDaoImpl implements AccountDao {@Overridepublic Account queryAccountByCardNo(String cardNo) throws Exception {//从连接池获取连接Connection con = Instance().getConnection();String sql = "select * from account where cardNo=?";PreparedStatement preparedStatement = con.prepareStatement(sql);preparedStatement.setString(1, cardNo);ResultSet resultSet = uteQuery();Account account = new Account();// 结果封装while (()) {account.String("cardNo"));account.String("name"));account.Int("money"));}resultSet.close();preparedStatement.close();con.close();return account;}@Overridepublic int updateAccountByCardNo(Account account) throws Exception {//从连接池获取连接Connection con = Instance().getConnection();String sql = "update account set money=? where cardNo=?";PreparedStatement preparedStatement = con.prepareStatement(sql);preparedStatement.setInt(1, Money());preparedStatement.setString(2, CardNo());int i = uteUpdate();preparedStatement.close();con.close();return i;}
}
问题分析
问题解决
1)new关键字代码耦合问题?对象的依赖关系如何确定?什么时候实例化对象?
解决方案:
2)没有事务控制,无法保证数据库操作的原子性?
解决方案:
<?xml version="1.0" encoding="UTF-8"?>
<beans><!--托管:创建Dao接口--><bean id="accountDao" class=j.dao.impl.JdbcAccountDaoImpl"></bean><bean id="transferService" class=j.service.impl.TransferServiceImpl"><property name="accountDao" ref="accountDao"/></bean></beans>
/*** 任务一:解析xml配置文件,利用反射技术生产对应的实例对象。同时管理对象的注入问题* 任务二:提供静态方法根据ID获取类对象** @Author zhichunqiu* @time 2020/6/3 14:56*/
public class BeanFactory {// 存储实例化的Beanprivate static Map<String, Object> beans = new HashMap<>();public static Object getBean(String name) {(name);}static {try {InputStream resourceAsStream = ClassLoader().getResourceAsStream(l");// 使用dom4j技术解析xml配置文件SAXReader saxReader = new SAXReader();Document document = ad(resourceAsStream);Element rootElement = RootElement();// 读取bean标签List<Element> elementList = rootElement.selectNodes("//beans/bean");// 实例化所有对象,并且放到Map中for (Element element : elementList) {String id = element.attributeValue("id");String clazz = element.attributeValue("class");Class<?> aClass = Class.forName(clazz);Object instance = wInstance();beans.put(id, instance);}// 维护bean之间的依赖关系List<Element> propertyList = rootElement.selectNodes("//bean/property");for (Element element : propertyList) {// 属性名称String name = element.attributeValue("name");// 应用类型的值IDString ref = element.attributeValue("ref");// 获取父标签的属性Element parentElement = Parent();String parentId = parentElement.attributeValue("id");Object o = (parentId);Method[] methods = o.getClass().getMethods();for (Method method : methods) {// 使用set方法注入if (Name().equalsIgnoreCase("set" + name)) {method.invoke(o, (ref));}}}System.out.println(beans);} catch (Exception e) {e.printStackTrace();}}
}
@WebServlet(name = "transferServlet", urlPatterns = "/transferServlet")
public class TransferServlet extends HttpServlet {// 获取TransferService对象private TransferService transferService = (TransferService) Bean("transferService");
}
public class TransferServiceImpl implements TransferService {private AccountDao accountDao;// set方式注入对象public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}
}
/*** Connecion获取类,与本地线程绑定* @Author zhichunqiu* @time 2020/6/3 18:55*/
public class ConnectionUtils {// 本地线程,存储连接private ThreadLocal<Connection> threadLocal = new ThreadLocal<>();// 从本地线程中获取连接,如果没有就从数据库连接池中获取并设置到本地线程public Connection getCurrentThreadConn() throws SQLException {Connection connection = ();if (connection == null) {connection = Instance().getConnection();threadLocal.set(connection);}return connection;}
}
j.utils;import java.sql.Connection;
import java.sql.SQLException;/*** 事务控制管理器** @Author zhang yong jun* @time 2020/6/3 19:02*/
public class TransactionManager {private ConnectionUtils connectionUtils;public void setConnectionUtils(ConnectionUtils connectionUtils) {tionUtils = connectionUtils;}// 开启事务public void start() throws SQLException {CurrentThreadConn().setAutoCommit(false);}// 提交事务public void commit() throws SQLException {CurrentThreadConn()mit();}// 回滚事务public void rollback() throws SQLException {CurrentThreadConn().rollback();}
}
j.factory;j.utils.TransactionManager;import flect.InvocationHandler;
import flect.Method;
import flect.Proxy;/*** 代理工厂,负责控制事务的开启,提交与回滚** @Author zhang yong jun* @time 2020/6/3 19:30*/
public class ProxyFactory {private TransactionManager transactionManager;public void setTransactionManager(TransactionManager transactionManager) {ansactionManager = transactionManager;}public Object getJdkProxy(Object obj) {Class().getClassLoader(), Class().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;try {// 代理对象开启事务transactionManager.start();// 执行原方法逻辑method.invoke(obj, args);// 提交事务transactionManagermit();} catch (Exception e) {// 异常回滚事务llback();// 异常由上层处理throw e;}return result;}});}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans><!--将ConnectionUtils工具类托管--><bean id="connectionUtils" class=j.utils.ConnectionUtils"></bean><!--托管:创建Dao接口--><bean id="accountDao" class=j.dao.impl.JdbcAccountDaoImpl"><property name="connectionUtils" ref="connectionUtils"/></bean><bean id="transferService" class=j.service.impl.TransferServiceImpl"><property name="accountDao" ref="accountDao"/></bean><!--托管:创建事务管理对象--><bean id="transactionManager" class=j.utils.TransactionManager"><property name="connectionUtils" ref="connectionUtils"/></bean><!--托管:创建代理工厂对象--><bean id="proxyFactory" class=j.factory.ProxyFactory"><property name="transactionManager" ref="transactionManager"/></bean></beans>
/*** @author zhichunqiu*/
public class JdbcAccountDaoImpl implements AccountDao {private ConnectionUtils connectionUtils;// 注入对象public void setConnectionUtils(ConnectionUtils connectionUtils) {tionUtils = connectionUtils;}@Overridepublic Account queryAccountByCardNo(String cardNo) throws Exception {//从连接池获取连接
// Connection con = Instance().getConnection();// 改为注入
// Connection con = CurrentThreadConn();Connection con = CurrentThreadConn();String sql = "select * from account where cardNo=?";PreparedStatement preparedStatement = con.prepareStatement(sql);preparedStatement.setString(1, cardNo);ResultSet resultSet = uteQuery();Account account = new Account();while (()) {account.String("cardNo"));account.String("name"));account.Int("money"));}resultSet.close();preparedStatement.close();// 从本地线程获取连接,不可以释放,否则就解除了绑定
// con.close();return account;}@Overridepublic int updateAccountByCardNo(Account account) throws Exception {
// Connection con = Instance().getConnection();// 改为注入
// Connection con = CurrentThreadConn();Connection con = CurrentThreadConn();String sql = "update account set money=? where cardNo=?";PreparedStatement preparedStatement = con.prepareStatement(sql);preparedStatement.setInt(1, Money());preparedStatement.setString(2, CardNo());int i = uteUpdate();preparedStatement.close();
// con.close();return i;}
}
@WebServlet(name = "transferServlet", urlPatterns = "/transferServlet")
public class TransferServlet extends HttpServlet {// 获取代理工厂private ProxyFactory proxyFactory = (ProxyFactory) Bean("proxyFactory");// 从代理工厂中使用JDK代理返回TransferService对象private TransferService transferService = (TransferService) Bean("transferService"));
}
总结
截止目前,我们已经完成了《银行转账》案例基础到问题分析,然后基于IoC和AOP思想的改造。从而实现了对象统一管理和依赖注入、事务管理控制的问题。其实这些就是Spring框架的IoC和AOP原理。
挑战
本文发布于:2024-02-01 08:23:02,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170674698235202.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |