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。

IoC和DI描述的是一件事情。(对象实例化及依赖关系维护),只不过角度不同。
IOC: 站在对象角度,对象实例化以及管理权力交给了容器
DI:站在容器角度。容器会把依赖的其他对象注入
 
 

1.6 AOP编程思想

1)什么是AOP?
Aspect Oriented Programming。面向切面编程
AOP是OOP的延续。
 

 

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创建

 

posted @ 2024-02-19 12:41  ylxn  阅读(2)  评论(0编辑  收藏  举报