Spring核心结构
Spring的核心思想
AOP
- OOP:面向对象编程,特征是继承,封装,多态,解决垂直体系的代码重复
- AOP:面向切面,解决横切代码的重复问题,以及抽取非业务代码,明确业务逻辑.常见应用有事务控制,日志记录,权限控制等
IOC
控制反转: 对象创建交由外部容器实现,解决对象间的耦合.
DI
依赖注入:与IOC角度不同,IOC是站在对象角度上,对象的创建交由容器维护,DI是站在容器的角度上,容器会提供对象依赖的其他对象,供给其使用
MVC的发展
传统MVC
// Controller持有Service对象
public class TransferServlet extends HttpServlet {
private TransferService transferService = new TransferServiceImpl();
}
// Service持有Dao对象
public class TransferServiceImpl implements TransferService {
private AccountDao accountDao = new JdbcAccountDaoImpl();
}
问题
1.代码耦合,每层都持有下一层的实现类对象
2.service层没有进行事务控制,方法执行中出现异常时,可能会导致数据库数据错乱
解决方案
问题1:
除了通过new创建对象外,我们还可以通过反射的方式创建,可以将对象创建提取到一个统一的地方执行,并提供一个方法去获取对象.如工厂类
问题2:
为Service层添加事务控制,但是JDBC的事务是控制在dao层,若一个service层中调用dao层多个db方法,这样就会导致出现多个事务,我们需要让这多个db方法属于一个Connection,这样才能实现Service层的事务控制.
代码示例
1.提取对象到XML
<beans>
<bean id="transferService"
class="com.ww.transfer.service.impl.TransferServiceImpl">
<property name="AccountDao" ref="accountDao"/>
</bean>
<bean id="accountDao"
class="com.ww.transfer.dao.impl.JdbcAccountDaoImpl">
</bean>
</beans>
2.通过工厂类创建对象
public class BeanFactory {
/**
* ⼯⼚类的两个任务
* 任务⼀:加载解析xml,读取xml中的bean信息,通过反射技术实例化bean对象,然后放⼊
* map待⽤
* 任务⼆:提供接⼝⽅法根据id从map中获取bean(静态⽅法)
*/
private static final Map<String, Object> map = new HashMap<>();
static {
// 读取配置对象信息的XML文件
InputStream resourceAsStream =
BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read(resourceAsStream);
Element rootElement = document.getRootElement();
// 获取所有bean节点
List list = rootElement.selectNodes("//bean");
// 实例化bean对象
for (Object value : list) {
Element element = (Element) value;
// 获取ID
String id = element.attributeValue("id");
// 获取类全限定名
String clazz = element.attributeValue("class");
Class<?> aClass = Class.forName(clazz);
Object o = aClass.newInstance();
map.put(id, o);
}
// 维护bean之间的依赖关系
List propertyNodes =
rootElement.selectNodes("//property");
for (Object propertyNode : propertyNodes) {
Element element = (Element) propertyNode;
// 处理property元素
String name = element.attributeValue("name");
String ref = element.attributeValue("ref");
// 获取外层Bean的对象
String parentId =
element.getParent().attributeValue("id");
Object parentObject = map.get(parentId);
// 调用setter方法
Method[] methods = parentObject.getClass().getMethods();
for (Method method : methods) {
if (("set" + name).equalsIgnoreCase(method.getName())) {
// bean之间的依赖关系(注⼊bean)
Object propertyObject = map.get(ref);
method.invoke(parentObject, propertyObject);
}
}
// 维护依赖关系后重新将bean放⼊map中
map.put(parentId, parentObject);
}
} catch (DocumentException | ClassNotFoundException | IllegalAccessException | InstantiationException |
InvocationTargetException e) {
e.printStackTrace();
}
}
public static Object getBean(String id) {
return map.get(id);
}
}
3.增加ConnectionUtils维护唯一Connection
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;
}
}
4.增加ProxyFactory生成代理类,插入事务处理逻辑
public class ProxyFactory {
private TransactionManager transactionManager;
public void setTransactionManager(TransactionManager
transactionManager) {
this.transactionManager = transactionManager;
}
// 生成代理类
public Object getProxy(Object target) {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(), (proxy, method, args) -> {
Object result;
try {
// 开启事务
transactionManager.beginTransaction();
// 调⽤原有业务逻辑
result = method.invoke(target, args);
// 提交事务
transactionManager.commit();
} catch (Exception e) {
e.printStackTrace();
// 回滚事务
transactionManager.rollback();
// 异常向上抛出,便于servlet中捕获
throw e.getCause();
}
return result;
});
}
}