Spring_第六章【Spring知识点总结】

1:spring 创建对象的过程和spring bean生命周期

在如下代码中,我们通过application接口读取配置文件之后,通过debug代码查看源代码

 ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

 Service1Impl service1impl= (Service1Impl) context.getBean("service1");

进入到refresh方法中,可以看到如下的bean实例化过程,整个过程的流程图如下:

代码的执行逻辑如下: 

2:循环依赖和三级缓存

2.1:什么是循环依赖

两个类互相引用

2.2:怎么解决循环依赖(三级缓存) 

循环依赖的解决,首先我们知道构造函数创建对象的时候,对象会先初始化分配内存空间,然后实例化给属性赋值。这里两个步骤是分开。就像我们单例的双重验证一样。所以这就给循环依赖提供了解决空间。

1:我们先初始化A,发现A依赖B,然后把A的初始化放到三级缓存中,此时的A不完整。

2:然后去初始化B,B循环下边的代码,在一二级缓存中找不到A,A没有完成完全的初始化,三级缓存可以找到A.此时B完成了完整的初始化,把B放入到一级缓存

3:然后A接着初始化,在一级缓存中找到了B,也就完成了A的初始化了

我们查看源码分析解决方案:

 public static void main(String[] args) {
        @Nullable
        protected Object getSingleton(String beanName, boolean allowEarlyReference) {
            // Quick check for existing instance without full singleton lock
            //1:一级缓存中有没有已经存在的bean
            Object singletonObject = this.singletonObjects.get(beanName);
            //2:一级缓存单例池中不存在 并且正在创建
            if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
                //3:从二级缓存中获取bean
                singletonObject = this.earlySingletonObjects.get(beanName);
                //4:二级缓存也没有 并且允许循环依赖
                if (singletonObject == null && allowEarlyReference) {
                    synchronized (this.singletonObjects) {
                        // Consistent creation of early reference within full singleton lock
                        //5:前边可能在创建的过程中,此处一级缓存再次查询bean
                        singletonObject = this.singletonObjects.get(beanName);
                        //6:一级缓存不存在 
                        if (singletonObject == null) {
                            //7:二级缓存再次查询
                            singletonObject = this.earlySingletonObjects.get(beanName);
                            if (singletonObject == null) {
                                //8:二级缓存不存在 查询三缓
                                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                                if (singletonFactory != null) {
                                    //9:三缓存在 将三缓存入二缓,并且移除三缓
                                    singletonObject = singletonFactory.getObject();
                                    this.earlySingletonObjects.put(beanName, singletonObject);
                                    this.singletonFactories.remove(beanName);
                                }
                            }
                        }
                    }
                }
            }
            return singletonObject;
        }
    }

循环依赖解决依赖spring的内部三级缓存:

/** 一级缓存:完整的bean,没有循环依赖 Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** 二级缓存:用来解决AOP切面 Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

/** 三级缓存:存放不完整的bean,用来解决循环依赖,并且将aop的切面代理bean放入二级缓存  Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

3:spring的注解

注解作用备注
@Component(value = "people")定义一个bean,并且指定bean的名字作用在类上能实现对所有的类进行注解,但是Component不利于三层架构,所以一个注解扩展成了三个来对应不同的业务逻辑层。
@Controller对应业务的controller作用在类上
@Service对应业务的service作用在类上
@Dao对应业务的dao作用在类上
@Autowired
@Qualifier(value = "dog222")
Autowired自动注入通过byType,但是有时候接口有两个实现类,需要Qualifier指定具体的接口实现名字作用在属性字段上
@Resource(name = "cat11")作用和Autowired一致,是java注
解,按照类型ByType和ByName指定bean的名字
作用在属性字段上
@scope("singleton")设置bean的作用域 默认是单例作用的类上
@Lazy(value = false)设置bean的加载机制 默认容器启动的时候加载作用在类上
 @PostConstruct设置bean的初始化的时候执行的方法作用在方法上
 @PreDestroy设置bean在容器关闭的时候实行的方法,只有单例有效作用在方法上
 @Value("huyiju")
    private String name;
给属性注入值作用在属性字段上
@Configuration
public class ConfigBean {
    @Bean //bean的名字就是方法名字
    public Cat getCat(){
        return new Cat();
    }

    @Bean//bean的名字就是方法名字
    public Dogs getDog(){
        return new Dogs();
    }
}
@Configuration的作用跟Component相似但是 Configuration里边看可以有多个bean,通过bean的id就是方法名

4:springIoc

bean的ioc就是将以前我们手动创建的对象现在由容器管理

5:springAop

通过jdk和cglig来实现代理,将接口或者类的方法实现增强,从而实现比如事务,日志等通用操作
 

8:spring的设计模式

9:spring的事务和事务失效

9.1:spring的事务传播行为


    /**
     * 1:REQUIRED
     * 事务代码测试 简单的插入两个表的数据
     * 插入class表和student表
     */
    @Test
    public void REQUIRED() {
        ClassService classService = applicationContext.getBean("classServiceImpl", ClassService.class);
        Classs classs = new Classs();
        classs.setCaption("大学一年3");

        Student student = new Student();
        student.setSname("测试2333333");
        student.setSsex("男");
        student.setSdatetime(new Date());
        classService.REQUIRED(student, classs);
    }

    /**
     * 2:SUPPORTS
     * 调用者不开启事务就没有,开启的话按照事务执行
     * 自己失败 调用者也会回滚
     *
     */
    @Test
    public void SUPPORTS() throws Exception {
        ClassService classService = applicationContext.getBean("classServiceImpl", ClassService.class);
        Classs classs = new Classs();
        classs.setCaption("大学1");

        Student student = new Student();
        student.setSname("测试");
        student.setSsex("男");
        student.setSdatetime(new Date());
        classService.SUPPORTS(student, classs);
    }


    /**
     * 3:NOT_SUPPORTED
     * 不会跟随调用者事务
     * 调用者提交 回滚 都不会影响自己
     *
     * NEVER 报错 父方法不能有事务
     */
    @Test
    public void NOT_SUPPORTED() {
        ClassServiceController classServiceController = applicationContext.getBean("classServiceController", ClassServiceController.class);
        Classs classs = new Classs();
        classs.setCaption("一年级");

        Student student = new Student();
        student.setSname("测试hu");
        student.setSsex("男");
        student.setSdatetime(new Date());
        classServiceController.NOT_SUPPORTED(student, classs);
    }


    /**
     * 4:REQUIRES_NEW
     * 不管调用者有没有事务  自己都会开启事务 自己的事务提交或者回滚不影响调用者
     */
    @Test
    public void REQUIRES_NEW() {
        ClassService classService = applicationContext.getBean("classServiceImpl", ClassService.class);
        Classs classs = new Classs();
        classs.setCaption("一年级2");

        Student student = new Student();
        student.setSname("测试hu");
        student.setSsex("男");
        student.setSdatetime(new Date());
        classService.REQUIRES_NEW(student,classs);
    }

    /**
     * 5:MANDATORY
     * 调用者必须得有事务 否则报错
     */
    @Test
    public void MANDATORY() {
        ClassService classService = applicationContext.getBean("classServiceImpl", ClassService.class);
        Classs classs = new Classs();
        classs.setCaption("一年级5");

        Student student = new Student();
        student.setSname("测试5");
        student.setSsex("男");
        student.setSdatetime(new Date());
        classService.mandatory(student,classs);
    }

    /**
     * 6:NESTED
     * 自己出异常不会影响调用者
     * 调用者异常 全部的自己回滚
     */
    @Test
    public void NESTED() {
        ClassService classService = applicationContext.getBean("classServiceImpl", ClassService.class);
        Classs classs = new Classs();
        classs.setCaption("一年级6");

        Student student = new Student();
        student.setSname("测试6");
        student.setSsex("男");
        student.setSdatetime(new Date());
        classService.NESTED(student,classs);
    }

    /**
     * propagation 事务传播行为
     *
     * REQUIRED(0),表示当前运行在事务中,有的话直接用 没有的话就开启事务 执行结果:多表插入有事务,要么成功要么失败
     * SUPPORTS(1),表示跟随事务,有的话也可以,没有的话也可以, 执行结果:多表插入没有事务 有的成功有的失败
     * MANDATORY(2),调用者必须得有事务 否则报错
     * REQUIRES_NEW(3),不管调用者有没有事务  自己都会开启事务 自己的事务提交或者回滚不影响调用者
     * NOT_SUPPORTED(4),表示不跟随事务,老大的事务跟我没有关系
     * NEVER(5),表示不能有事务,老大有事务就会报错
     * NESTED(6);自己出异常不会影响调用者,调用者事务回滚 自己也要回滚
     */

9.2:spring的事务失效

//1:异常问题:在业务代码中如果抛出RuntimeException异常,事务回滚;但是抛出Exception,事务不回滚;

//2:异常问题:如果在加有事务的方法内,使用了try...catch..语句块对异常进行了捕获,
// 而catch语句块没有throw  new RuntimeExecption异常,事务也不会回滚

//3:方法内部调用:(切面切的是方法) 方法里边 链式调用 不行因为事务的本质是动态代理生成代理对象,然后根据方法进行增强 链式调用无效
// 在类A里面有方法a 和方法b,
// 然后方法b上面用 @Transactional加了方法级别的事务,在方法a里面 调用了方法b
// 方法b里面的事务不会生效。原因是在同一个类之中,方法互相调用,切面无效 ,而不仅仅是事务。这里事务之所以无效,是因为spring的事务是通过aop实现的。

//4:错误的传播行为

//5:spring管理异常

10:applicationcontext和beanfactory

beanfactory是个顶级接口,里边都是getbean的各种方法,用来获取bean。但是这个接口的实现类不会实例化bean,只会被动的获取的时候创建bean。该代码已经不推荐使用了

 ClassPathResource res = new ClassPathResource("beans.xml");
 BeanFactory beanFactory=new XmlBeanFactory(res);
 beanFactory.getBean("bean名字");

application接口继承的bean factory接口。里边的方法很多,继承了各种接口,他的实现类ClassPathXmlApplicationContext,会有bean工厂,能够按照我们上边的生命周期来实例化bean,bean都会存在,我们通过getbean获取即可

 ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

 Service1Impl service1impl= (Service1Impl) context.getBean("service1");
 service1impl.say();

结论:几乎所有的应用场合我们都直接使用ApplicationContext 而非底层的BeanFactory。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值