week15_day02_Spring_IOC&&DI&&ApplicationContext&&lombok&&xml文件中注册bean的方式&&生命周期

总结昨天的内容:

  1. 设计模式
    最佳实践(经验)

  2. 特点
    s:单一职责
    o:开闭原则
    l:里氏替代原则
    i:接口隔离
    d:依赖倒置

  3. 具体的设计模式

3.1单例(重要)
应用程序对应的实例只有一个

1、构造方法私有
2、包含自己的成员变量
3、提供静态方法给其他人调用

线程不安全的懒加载(在方法上开始初始化的)
线程安全的懒加载(在方法上开始初始化的,并且在方法上加锁sync)
线程安全的立即加载(在静态成员变量上直接初始化)
线程安全的立即加载(在静态代码块中初始化)
线程安全的懒加载(静态内部类实现,当你调用到静态内部类的方法的时候,静态内部类才加载) → 将实例初始化的过程放在了静态内部类中

3.2工厂

3.2.1简单工厂
给工厂方法的形参中 给不同的值,生产出的实例有所不同
当需要新的生产实例的时候,需要去修改工厂的生产方法

3.2.2工厂方法
更好的满足了开闭原则
提供一个工厂接口,提供生产方法的规范

具体的工厂实现工厂接口,在具体的工厂中提供详细的生产方法

3.2.3使用方式

3.2.3.1实例工厂
工厂中的生产方法非静态方法
先对工厂进行实例化,然后通过工厂对象来调用生产方法

3.2.3.2静态工厂
工厂中的方法是静态方法,可以直接调用。静态工厂类似于工具类。

3.3代理(非常重要)
给委托类实现原有的功能的基础上,并且进行增强

3.3.1静态代理

3.3.1.1委托类成员变量
委托类以代理类中的成员变量的形式存在,可以调用委托类对象的方法
在HouseProxy中定义了一个HouseOwner的成员变量

3.3.1.2代理类继承委托类
重写父类(委托类)的方法,并且在重写的方法中调用父类的方法(super来调用)

3.3.2动态代理
都是要获得一个代理对象,通过代理对象调用的方法才是增强的方法

3.3.2.1jdk动态代理
类要有接口的实现,生成的代理对象和接口相关。并且要用接口来接收。

HelloService helloService = new HelloServiceImpl();
Object proxy = Proxy.newProxyInstance(classloader,interfaces,new InvocationHandler(){
	public Object invoke(proxy,method,args){
	//前面的增强
	Object object = method.invoke(helloSerivce,args);
	//后面的增强
	return object;
}
});

Object proxy只能用接口来接收,不能用实现类。

3.3.2.2cglib动态代理

invocationHandler和jdk动态代理的invocationHandler是不同包下的,不是同一个
Object proxy = Enhancer.create(class,new InvocationHandler(){
	public Object invoke(proxy,method,args){
	//前面的增强
	Object object = method.invoke(helloSerivce,args);
	//后面的增强
	return object;
}
});

Object proxy可以用接口也可以用实现类来接收。
因为cglib的实现是用代理类继承委托类。根据里氏替换原则,可以用父类接收子类。

3.4建造者builder
更侧重于设置参数的过程

在builder中 在创建builder时(生产之前)已经完成了实例化
需要保证始终对同一个实例设置参数,实例就要求是全局变量

set方法如果想要连续用起来,要求这些set方法的返回值为builder
.setHeadIq(120).setHeadEq(120).setLegLength()


Spring介绍(4天)
SpringIOC
SpringAOP
Spring事务


Spring 概念
Spring框架其实就是偏基础性的框架。可以去整合其他框架。类似于平台。
核心:IOC、DI和AOP

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。
它是为了解决企业应用开发(JavaEE)的复杂性而创建的。框架的主要优势之一就是其分层架构(MVC分层),分层架构允许使用者选择使用哪一个组件,同时为 J2EE(JavaEE) 应用程序开发提供集成的框架。
Spring是一个分层的Java SE/EE full-stack(一站式) 轻量级开源框架。


IOC&DI

IOC用于实例化类对象,管理类对象
IOC:Inverse of Controll 控制反转
控制:实例的生成权
反转:由应用程序反转给spring
容器:容器是放置实例对象的地方 → Spring容器、IOC容器

原先实例我们想用的时候自己new出来(主动的过程);到了Spring阶段,把实例的生成权交给了Spring容器,由Spring容器进行生成并管理,当我们想用的时候就从容器中取出来。

例子:小明挣了10块钱自己花。
小明找到了对象,挣的10块钱交给了对象。小明想花5毛,就要跟对象申请。

所谓IOC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。
所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

DI:Dependency Injection 依赖注入
应用程序(贫穷) ←→ Spring容器(富有)
经过了控制反转,谁富有谁贫穷
依赖:
谁依赖谁? 小张依赖他对象 → 应用程序依赖Spring容器
为什么依赖? 小张对象有钱 → Spring容器包含了应用程序必须的内容
注入
谁注入谁? Spring容器注入给应用程序
注入了什么?应用程序运行所必须的资源

谁依赖了谁:应用程序依赖于IOC容器
为什么要依赖:应用程序需要IOC容器来提供对象需要的外部资源
谁注入谁:IOC容器注入应用程序某个对象,应用程序依赖的对象
注入了什么:注入某个对象所需要的外部资源(包括对象、资源、常量数据)
在这里插入图片描述


aop:面向切面编程→ aspect oriented programming
oop→ object oriented programming


Spring Introduction
在这里插入图片描述
声明式事务支持:指定方法增加事务 → 通过注解指定方法 → 指哪儿打哪儿
事务 → 保证使用的是同一个connection → aop阶段会布置对应的作业

Spring的单元测试 → 提供了Spring环境


Spring 特点:
Core technologies: dependency injection, events, resources, i18n, validation, data binding, type conversion, SpEL, AOP.
依赖注入、资源、i18n国际化(springmvc)、校验(Springmvc)、数据绑定、类型转换(springmvc)、SpringExpressionLanguage、Aop(面向切面编程)
在这里插入图片描述


Spring Framework:
在这里插入图片描述

Core Container是Spring的核心组件。Spring的核心依赖就在这。
Spring的核心依赖:5+1
spring-core、spring-context、spring-aop、spring-beans、spring-expression
commons-logging(jcl)


写一个入门案例:

  1. 导入相关依赖:
    在这里插入图片描述
  2. 定义一个service
package com.cskaoyan.service;

public class HelloService {

    public void sayHello(String name) {
        System.out.println("hello " + name);
    }
}

想要通过Spring容器管理HelloService对象,就得先创建一个Spring容器。

  1. 创建Spring容器

通过Spring配置文件来管理组件
xml的文件 → 通常名字叫application(-xx).xml
既然是xml文件,文件要满足一定的约束(schema),约束就是规定你书写的格式是什么样的。

约束怎么来?
1、复制已有的配置文件的约束
2、从spring的参考文档上的appendix上复制
3、通过创建文件模板来使用 (推荐)效率高

第一次学习,我们只能通过第二种方式来使用。
在这里插入图片描述
有了第一次后,后面再创建Spring配置文件就用第三种方式:
那么,如何创建文件模板?
a. 创建
在这里插入图片描述
在这里插入图片描述
b. 使用模板
选择自己创建的模板
在这里插入图片描述
在这里插入图片描述
4. 将组件交给spring管理
组件:交给spring容器管理的实例,我们称之为组件
注册:在spring的配置文件中如何定义实例
HelloService交给Spring管理,这个过程叫做注册
在这里插入图片描述
将控制权反转也是通过反射技术来实现的。Spring通过class就能生产处这个类的实例对象。

  1. 从容器中取出实例进行使用
    locTest:
package com.cskaoyan;

import com.cskaoyan.service.HelloService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 入门案例1
 */
public class IocTest {

    @Test
    public void mytest1(){
        //初始化一个应用上下文,应用上下文是Spring容器一个高级功能的实现
        //再看ClassPath,表示类加载路径
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        //通过应用上下文从Spring容器中取出组件(实例)
        HelloService helloSerivce = (HelloService) applicationContext.getBean("helloSerivce");
        helloSerivce.sayHello("ligenli");
    }
}

这段代码中用到了ClassPath,下面就来讲一下classpath(类加载路径)。

a. maven的classpath
maven是根据文件夹名和目录结构来决定classpath

--src
	--main
		--java
		--resources

java和resources是maven项目的classpath

4.2idea中的classpath
应用要在idea中跑起来
在这里插入图片描述
在这里插入图片描述


locTest:

package com.cskaoyan;

import com.cskaoyan.service.HelloService;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 入门案例1
 */
public class IocTest {

    @Test
    public void mytest1() {
        //初始化一个应用上下文,应用上下文是Spring容器一个高级功能的实现
        //再看ClassPath,表示类加载路径
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        //通过应用上下文从Spring容器中取出组件(实例)
        HelloService helloService = (HelloService) applicationContext.getBean("helloService");
        helloService.sayHello("ligenli");

        // 1、指定id获得实例对象
        // 2、指定类型(class)获得实例对象
        // 3、1+2,即指定id和class
        //条件:这个类型(class)的组件在容器中只有这一个
        HelloService helloService2 = (HelloService) applicationContext.getBean(HelloService.class);
        helloService2.sayHello("加油吧!");
        HelloService helloService3 = applicationContext.getBean("helloService", HelloService.class);
        helloService3.sayHello("just be you");
    }

    @Test
    public void mytest2(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        //从容器中,取出指定id的组件多次,看是否是同一个组件
        Object helloService = applicationContext.getBean("helloService");
        Object helloService2 = applicationContext.getBean("helloService");
        Object helloService3 = applicationContext.getBean("helloService");
        Object helloService4 = applicationContext.getBean("helloService");
        Object helloService1 = applicationContext.getBean("helloService");
        Assert.assertEquals(helloService,helloService2);
    }
}

在这里插入图片描述


入门案例2
也是通过spring容器管理组件;
管理多个组件 → 多个组件之间有依赖关系
HelloService依赖于HelloDao → 在Spring容器中如何维护多个组件之间的关系

  1. 导包
  2. 构建业务代码

HelloDao :

package com.cskaoyan.dao;

public interface HelloDao {
    public void daoSayHello(String name);
}

HelloDaoImpl :

package com.cskaoyan.dao;

public class HelloDaoImpl implements HelloDao{
    @Override
    public void daoSayHello(String name) {
        System.out.println("hello " + name);
    }
}

HelloService :

package com.cskaoyan.service;

public interface HelloService {

    public void sayHello(String name);
}

HelloServiceImpl :

package com.cskaoyan.service;

import com.cskaoyan.dao.HelloDao;
import com.cskaoyan.dao.HelloDaoImpl;

public class HelloServiceImpl implements HelloService{

    //我们自己不实例化对象,让Spring来帮我们实例化
    //HelloDao helloDao = new HelloDaoImpl();
    HelloDao helloDao;

    @Override
    public void sayHello(String name) {
        helloDao.daoSayHello(name);
    }

    public HelloDao getHelloDao() {
        return helloDao;
    }

    public void setHelloDao(HelloDao helloDao) {
        this.helloDao = helloDao;
    }
}

  1. 注册组件并维护组件之间的关系
    在这里插入图片描述
    不能写接口,因为Spring管理组件的底层是通过反射实现的,给一个接口,如何实例化出对象呢?
    在这里插入图片描述
  2. 使用
package com.cskaoyan;

import com.cskaoyan.dao.HelloDao;
import com.cskaoyan.service.HelloService;
import com.cskaoyan.service.HelloServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {

    @Test
    public void mytest(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        //HelloServiceImpl bean = applicationContext.getBean(HelloServiceImpl.class);
        //spring建议通过接口的类型取出,更容易规范你能去做的事情
        //比如给spring的组件增强,比如使用jdk动态代理的方式进行增强,那么增强后的组件和接口是相关联的
        HelloService helloService = applicationContext.getBean(HelloService.class);
        helloService.sayHello("songge");
    }
    @Test
    public void mytest2(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        HelloService helloService = applicationContext.getBean(HelloService.class);
        helloService.sayHello("songge");
        HelloDao helloDao = applicationContext.getBean(HelloDao.class);
        System.out.println(111);
    }
}

总结:Spring在这里有没有带来新的功能?并没有
调用的都是原有的方法sayHello和daoSayHello
但是提高了组件的重用频率
类似于搭积木,你需要什么样子的,就从容器中取出来。

学习了IOC 和 DI 最大的感触是什么?
控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法
依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。


Spring 核心API:

ApplicationContext
	ClassPathXmlApplicationContext
	FileSystemXmlApplicationContext

在这里插入图片描述
都是去加载application
ClasspathXmlApplicationContext 加载classpath目录下的配置文件
FileSystemXmlApplicationContext 加载文件系统目录下的配置文件

package com.cskaoyan;

import com.cskaoyan.service.HelloService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class MyTest {

    @Test
    public void mytest(){
        //从classpath加载配置文件→ java或resources目录
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        HelloService bean = applicationContext.getBean(HelloService.class);
    }
    @Test
    public void mytest2(){
        //D:\WorkSpace\j22_workspace\codes\day02-spring-ioc\demo3-applicationContext\src\main\resources\application.xml
        String fileSystemPath = "D:\\WorkSpace\\j22_workspace\\codes\\day02-spring-ioc\\" +
                "demo3-applicationContext\\src\\main\\resources\\application.xml";
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext(fileSystemPath);
    }
}


BeanFactory
在这里插入图片描述
在这里插入图片描述
BeanFactory:容器中所有的组件都是通过这个Bean生产出来的

BeanFactory:生产所有组件bean
FactoryBean:XXXFactoryBean,factoryBean对应的特定的xxx实例。即生产特定的Bean。


讲一个辅助编译的工具:Lombok
帮我们生成getter、setting、equal、hashcode、toString、有参无参构造方法
使用起来非常简单

  1. 引入依赖
    在这里插入图片描述
  2. 安装插件
    避免一些编译报错
    在这里插入图片描述
    可以选择离线下载
    在这里插入图片描述
  3. 使用lombok
    在这里插入图片描述
    会发现字节码文件中是这样的:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.cskaoyan.component;

public class NoArgsConstructorBean {
    String name;
    Integer id;

    public NoArgsConstructorBean() {
    }

    public String getName() {
        return this.name;
    }

    public Integer getId() {
        return this.id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof NoArgsConstructorBean)) {
            return false;
        } else {
            NoArgsConstructorBean other = (NoArgsConstructorBean)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$name = this.getName();
                Object other$name = other.getName();
                if (this$name == null) {
                    if (other$name != null) {
                        return false;
                    }
                } else if (!this$name.equals(other$name)) {
                    return false;
                }

                Object this$id = this.getId();
                Object other$id = other.getId();
                if (this$id == null) {
                    if (other$id != null) {
                        return false;
                    }
                } else if (!this$id.equals(other$id)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof NoArgsConstructorBean;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $name = this.getName();
        int result = result * 59 + ($name == null ? 43 : $name.hashCode());
        Object $id = this.getId();
        result = result * 59 + ($id == null ? 43 : $id.hashCode());
        return result;
    }

    public String toString() {
        return "NoArgsConstructorBean(name=" + this.getName() + ", id=" + this.getId() + ")";
    }
}

在这里插入图片描述
通常@AllArgsConstructor和@NoArgsConstructor同时出现
因为增加了有参构造方法会覆盖掉默认的无参构造方法,后续使用框架里底层很多用到反射,反射又经常使用到无参构造方法,通常需要额外增加@NoArgsConstructor


xml文件中注册bean的方式

构造方法
无参构造(最常用)
因为默认提供的是无参构造,这个是最常用

NoArgsConstructorBean :

package com.cskaoyan.component;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 无参构造方法
 * 默认包含无参的构造方法
 */
@Data
@NoArgsConstructor
public class NoArgsConstructorBean {
    String name;
    Integer id;
}

在application.xml中的配置:
在这里插入图片描述

有参构造:

HasArgsConstructorBean :

package com.cskaoyan.component;

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * 有参构造方法
 */
@AllArgsConstructor //写了有参构造方法,会将默认的无参构造方法覆盖掉
@Data
public class HasArgsConstructorBean {
    String name;
    Integer id;

    //public HasArgsConstructorBean(String name, Integer id) {
    //    this.name = name;
    //    this.id = id;
    //}
}

在application.xml中的配置:
在这里插入图片描述


工厂
通常是整合已有代码的时候,可以使用工厂注册组件(比如你写了一个工具类)
在这里插入图片描述
实例工厂:
在这里插入图片描述
静态工厂:
在这里插入图片描述


生命周期:

Spring中bean的生命周期
并不是所有的bean都会执行完所有的声明周期。
默认只会执行到1和2。之后这些需要满足一定的条件才能执行到。
6和9做的事情很类似,只不过和7、8之间有一个顺序关系。

在这里插入图片描述
默认是不会执行红框框中的生命周期的,只有实现了这些接口才会执行。

在这里插入图片描述
LifeCycleBean代码:
在这里插入图片描述

CustomBeanPostProcessor代码:
在这里插入图片描述
测试代码:

package com.cskaoyan.bean;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class LifeCycleTest {

    @Test
    public void mytest1(){
        //执行完这行代码就意味着组件可以使用了,也就是1-9的生命周期都执行完了
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        //不需要取出组件,生命周期就已经开始
        //关闭上下文后就会执行10、11生命周期
        applicationContext.close();
    }
}

执行结果:
在这里插入图片描述
可以利用生命周期的先后顺序写一些简单的业务逻辑。


作业:使用spring为项目里的所有类的所有方法增加
写几个不同的bean ,每个bean里包含不同的方法。
通过spring 使得调用任何一个实现方法之前和之后都增加一些内容输出。(通过PostBeanProcessor实现)
提示:生命周期 动态代理
提示:狸猫换太子

举个例子:比如有几个类Cat、Dog、Tiger,这几个类中分别有miao、wang、wuuu这几个方法,那么从容器中取出组件,调用这几个方法的时候(注意不是容器初始化时),miao、wang、wuuu这几个方法执行之前都会输出hello,执行之后都会输出world

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-玫瑰少年-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值