IOC容器设计学习
Spring简介:
- 以IOC与AOP为内核。分层框架。轻量级(不需要依赖其他软件,只需要JVM,容器环境)
Spring 的核心结构
每个模块对应一个Jar包。
1.4 IOC思想讲解
IOC和AOP不是Spring提出的。spring在技术上很好的把这两个思想实现
1)什么是IoC
Inversion of Control. (控制反转),这是一个技术思想。
描述的事情:Java开发领域对象创建的管理问题:
传统:A依赖B,会在A中new一个 B。
IoC思想的开发方式:不用自己new 对象了,由IoC容器帮助我们实例化对象,并且管理,我们需要使用哪个对象,去跟IoC容器要
我们丧失了创建管理对象的能力,得到了福利(不用考虑对象创建、管理和一系列事情)
控制:指的是对象创建(实例化)的权利
反转:控制权交给外部,(Spring框架,IoC容器)
2)IoC解决了什么问题
解决了对象之间的耦合问题
如果DaoImpl改了名字,则左侧两处代码都要改。
改进:
3)IoC和DI的区别
IoC和DI。
1.6 AOP编程思想
OOP思想可以解决大多数代码重复问题,但是有一些是处理不了的,假如需要加入性能监控
public class Animal { public void eat(){ long startTime = System.currentTimeMillis(); long endTime = System.currentTimeMillis(); } public void run(){ long startTime = System.currentTimeMillis(); long endTime = System.currentTimeMillis(); } }
横切逻辑代码使用场景有限:事务控制、权限校验、日志打印
横切代码存在的问题:
- 横切代码重复
- 入侵业务逻辑
AOP解决,在不改变原有业务逻辑情况下,增强横切逻辑代码,避免代码重复
为什么叫面向切面编程:
原有业务代码不能动,只能操作横切逻辑代码。所以是面向横切逻辑
面:横切逻辑影响很多方法,每一个方法是一个点,组在一起是个面
1.7 Ioc与AOP问题分析
Service层需要添加事务控制,出现异常可能会导致数据错乱
1)除了new 实例化对象,还可以使用反射. Class.forName('路径')
2)使用工厂来通过反射技术生产对象,工厂模式是解耦合非常好的一种方式(工厂类解析xml,然后反射实例化对象)
xml:
<?xml version="1.0" encoding="UTF-8" ?> <!--跟标签beans,里面配置一个又一个的bean子标签,每一个bean子标签都代表一个类的配置--> <beans> <!--id标识对象,class是类的全限定类名--> <bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcAccountDaoImpl"> <property name="ConnectionUtils" ref="connectionUtils"/> </bean> <bean id="transferService" class="com.lagou.edu.service.impl.TransferServiceImpl"> <!--set+ name 之后锁定到传值的set方法了,通过反射技术可以调用该方法传入对应的值--> <property name="AccountDao" ref="accountDao"></property> </bean> <!--配置新增的三个Bean--> <bean id="connectionUtils" class="com.lagou.edu.utils.ConnectionUtils"></bean> <!--事务管理器--> <bean id="transactionManager" class="com.lagou.edu.utils.TransactionManager"> <property name="ConnectionUtils" ref="connectionUtils"/> </bean> <!--代理对象工厂--> <bean id="proxyFactory" class="com.lagou.edu.factory.ProxyFactory"> <property name="TransactionManager" ref="transactionManager"/> </bean> </beans>
3)单例模式(只有一个实例):
- 必须私有化构造方法,不让new
饿汉式:
package com.qcby.singleton; public class LazySingleton { private static LazySingleton instance; private LazySingleton(){} public static synchronized LazySingleton getInstance() { if(instance == null) { instance = new LazySingleton(); } return instance; } }
饿汉式:
package com.qcby.singleton; public class HungrySingleton { private HungrySingleton() {} private static final HungrySingleton instance = new HungrySingleton(); public static HungrySingleton getInstance() { return instance; } }
利用工程模式,xml配置方式创建对象
package com.lagou.edu.factory; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; public class BeanFactory { //读取xml //对外提供几口 private static Map<String, Object> map = new HashMap<>(); static { InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("bean.xml"); SAXReader saxReader = new SAXReader(); try { Document document = saxReader.read(inputStream); Element root = document.getRootElement(); List<Element> elements = root.selectNodes("//bean"); for(Element bean : elements){ String id = bean.attributeValue("id"); String clazz = bean.attributeValue("class"); Class<?> aClass = Class.forName(clazz); Object o = aClass.newInstance(); map.put(id, o); } //实例化完成后,维护对象的关系 有properties诉求的就有传值需求 List<Element> propertiesElements = root.selectNodes("//properties"); for(Element bean : propertiesElements) { String name = bean.attributeValue("name"); String ref = bean.attributeValue("ref"); //找到处理当前关系的bean Element parent = bean.getParent(); String parentId = parent.attributeValue("id"); Object po = map.get(parent.attributeValue("id")); Method [] methods = po.getClass().getMethods(); for(Method method : methods){ if(method.getName().equalsIgnoreCase("set"+name)){ method.invoke(po, map.get(ref)); } } // map.put(parentId, po); } } catch (DocumentException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } public static Object getBean(String name){ return map.get(name); } }
1.10 Ioc与AOP事务控制
数据库事务归根结底是Connection 事务 connection.commit();
accountDao.updateAccountByCardNo(to); int c = 1/0; accountDao.updateAccountByCardNo(from);
两个update使用了两个connection连接。这样肯定不是一个事务控制了。(解决:两次update属于一个线程内的调用,可以给当前线程绑定一个Connection)
package com.lagou.edu.utils; import java.sql.Connection; import java.sql.SQLException; public class ConnectionUtils { private static ConnectionUtils connectionUtils = new ConnectionUtils(); public static ConnectionUtils getInstance(){ return connectionUtils; } private ThreadLocal<Connection> local = new ThreadLocal<>(); private ConnectionUtils() { } public Connection getCurrentThreadConn() throws SQLException { Connection connection = local.get(); if(connection == null) { connection = DruidUtils.getInstance().getConnection(); local.set(connection); } return connection; } }
事务控制目前在dao层,没有在service层
package com.lagou.edu.service.impl; import com.lagou.edu.utils.ConnectionUtils; import java.sql.Connection; import java.sql.SQLException; public class TransferServiceImpl { public void transfer() throws SQLException { Connection connection = ConnectionUtils.getInstance().getCurrentThreadConn(); try { //关闭自动提交事务 connection.setAutoCommit(false); //提交事务 connection.commit(); } catch (Exception e){ e.printStackTrace();; //回滚事务 connection.rollback(); } } }
1.13 使用动态代理来实现横切逻辑
1)静态代理:
每一个接口对应一个代理类 静态代理
2)动态代理
不需要对每一个业务都new一个代理类
JDK动态代理
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; } }); }
cglib动态代理
动态代理工厂:
3)
package com.lagou.edu.proxy.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactory { private ProxyFactory() { } private static ProxyFactory proxy = new ProxyFactory(); public static ProxyFactory getInstance() { return proxy; } 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; System.out.println("start"); result = method.invoke(obj, args); System.out.println("end"); return result; } }); } }
1.15 使用动态代理改造service事务管理
private ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory"); private TransferService transferService = (TransferService) proxyFactory.getJdkProxy(BeanFactory.getBean("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 { // 设置请求体的字符编码 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");
2.1 IoC基础知识说明
IoC控制方式
- 纯xml
- 纯注解
- 半xml半注解
BeanFactory
- 对应不同应用和Bean创造方法有不同对应方式
- 需要自己写,才能配置相关Bean
2.4 创建Bean
- 推荐无参构建
- 静态方法(new 出来的对象加入容器进行管理)
- DI(依赖注入,可以通过容器给bean传值)
2.8 lazy-init
- 使用时候创建还是直接创建
- lazy-init 只适合singleton模式
2.9 FactoryBean
- 自定义Bean创建过程
- 可以生成某一个Bean类型的Bean实例
- 完成复杂的Bean创建