SSM学习笔记(二)——框架、Spring

框架是半成品软件,由它生成通用的程序,需要做的是补充配置信息,指导框架。由配置文件、注解两种方法实现。两者各有优缺点。配置文件可以统一配置,清晰明了;但代码量比较大。注解更简单便捷但信息不一目了然。

一、Spring简述:

Spring集成形框架,浅集成,更复杂。 1.0
SpringMVC属于Spring的web部分,是以Spring为基础二次开发形成的框架
SpingBoot是对Spring 的扩展,不仅仅是浅集成,深入集成,更加简便。 2.0
Spring Cloud是在SpringBoot基础上扩展的,完全针对于分布式、微服务的一套框架。 3.0
在这里插入图片描述

Spring的核心就是IOC和AOP。

IOC

  • IOC的本质就是——把bean的管理交给框架去做,spring自己维护一个bean容器,将所有bean进行统一管理,这样一来,所有需要用到实例的场景都不需要写繁琐且重复的实例化代码,而是——简单地完成bean声明和注入依赖就可以了。
class QueryController{
    UserService userService;
    BookService bookservice;
    QueryController() {
            //需要程序自己实例化对象。
        userService = new UserService;
        userService.setUserDao(new UserDao());
        bookservice = new BookService;
        bookservice.setBookDao(new BookDao());
    }
    public static void main(Strings[] args) {
        QueryController queryController = new QueryController();
    }
}
@Controller
class QueryController{
    @Autowired
    UserService userService;
    
    @Autowired
    BookService bookservice;
}

AOP

  • AOP的本质是——利用动态代理完成统一切面的功能,利用AOP,我们可以把一些横向的同一类型代码进行复用,比如登录拦截,身份校验,安全管理等等,这些——不需要内嵌到业务代码中,但却经常要用到的东西,就可以利用AOP来做成一个切面,然后指定需要拦截的方法,AOP通过动态代理会将切面代码加入到代理对象中,于是你执行业务代码时,相当于在执行代理对象,就会相应地调用切面方法。

一个最简单的动态代理实现如下:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
    public static void main(String[] args) {
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method);
                if (method.getName().equals("morning")) {
                    System.out.println("Good morning, " + args[0]);
                }
                return null;
            }
        };
        Hello hello = (Hello) Proxy.newProxyInstance(
            Hello.class.getClassLoader(), // 传入ClassLoader
            new Class[] { Hello.class }, // 传入要实现的接口
            handler); // 传入处理调用方法的InvocationHandler
        hello.morning("Bob");
    }
}

interface Hello {
    void morning(String name);
}

二、Spring的Bean

JavaBean(Java中的对象Bean)→ Spring的Bean既不用实现接口也不用继承父类,只用创建自己的类;Spring负责创建对象和处理关系。(由SPring创建对象交出创建对象权力的Bean就是Spring的Bean对象) ——Bean对象在beanfactory工厂创建——引入动态代理模式 ——SSM符合Spring的要求

(一)、Bean 的完整生命周期

记住
  1. spring负责实例化和关系注入——IOC的核心
  2. 实例化后依旧不可以对对象进行操作,还需要进行一系列的操作,也是丰富对象的过程
  3. 容器开对象创建,容器关对象才被销毁。

传统的Java应用中,bean的生命周期: 很简单,使用Java关键字 new 进行Bean 的实例化 → 然后该Bean 就能够使用了。 → 一旦bean不再被使用,则由Java自动进行垃圾回收。

Spring管理Bean的生命周期: 复杂多了,正确理解Bean 的生命周期非常重要,因为Spring对Bean的管理可扩展性非常强,下面展示了一个Bean的构造过程
在这里插入图片描述
如上图所示,Bean 的生命周期还是比较复杂的,下面来对上图每一个步骤做文字描述:

  1. Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化【beanfactory创建对象】

  2. Bean实例化后对将Bean的引入和值注入到Bean的属性中【依赖注入di,属性注入】

  3. 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法【名字方法注入】

  4. 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入【工厂方法注入】

  5. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。【上下文(对象创建时所带配置信息的指令等)】

  6. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。

  7. 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。

  8. 如果bean使用init-method声明了初始化方法,该方法也会被调用

  9. 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。

此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。【单例模式,保证对象使用,但该对象使用的生命周期被拉长了,长期占用内存】

  1. 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。——结束

(二)SpringBean循环依赖和三级缓存 🔍

三级缓存
https://www.cnblogs.com/semi-sub/p/13548479.html
https://baijiahao.baidu.com/s?id=1711380208642133437&wfr=spider&for=pc
只要两个缓存确实可以做到解决循环依赖的问题,但是有一个前提这个bean没被AOP进行切面代理,如果这个bean被AOP进行了切面代理,那么只使用两个缓存是无法解决问题

(三)、Bean的两种创建方式

注解逐渐替代XML配置文件

引入支持pom.xml

maven——简化jar的引入

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>5.3.4</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.3.4</version>
</dependency>

spring-beans——创建对象
spring-context——读上下文——读取配置文件

(1)基于配置文件的Bean

一般类 ——new对象

public class SomeBean {}
//调用
{
     SomeBean someBean = new SomeBean();
}
Spring配置文件创建Bean对象

【任意类都是对象,且类不能由new,不能创建对象。必须由Spring来创建对象】——单例,唯一对象
=>bean factory

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--SomeBean someBean = new SomeBean()-->
    <bean id="someBean" class="com.jd.javaconfig.SomeBean"></bean>
</beans>
 对比 
  SomeBean someBean = new SomeBean();
  <bean id="someBean" class="com.jd.javaconfig.SomeBean"></bean>
测试类1 ⭐
public class MyTest {
    @Test
    public void test1(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
        //读配置文件
        SomeBean sb = (SomeBean)ctx.getBean("someBean");
        //getBean获得对象
        System.out.println(sb);
        //使用
    }
}
(ClassPath☞类的根路径——src文件夹下)

src源文件,真正可以用的是编译后出现的class下的

(2)基于注解的Bean 👇

public class SomeBean {}
public class OtherBean {}
Spring注解创建Bean对象 ⭐

=>bean factory

// 作为Spring的主配置文件
@Configuration
public class AppConfig {
  //@Bean标签表示让Spring托管bean
  @Bean
  public SomeBean someBean(){
    return new SomeBean();
  }
  @Bean
  public OtherBean otherBean(){
    return new  OtherBean();
  }
}

AppConfig这个类是一个配置文件,不是XML配置文件——工厂模式

测试类2⭐
@Test
public void test() {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    //读取配置信息
    SomeBean sb = ctx.getBean(SomeBean.class);
    OtherBean ob = ctx.getBean(OtherBean.class);
    //getBean()获取对象
    System.out.println(sb);
    System.out.println(ob);
    //使用
}

这个是基于AnnotationConfigApplicationContext来配置的。(Annotation注解,Config配置)

到这里我们就已经学完了两个重要的标签 @Configuration和@Bean, @Configuration标签表示这个类可被Spring识别的配置对象的类,只有有这个标记的标签的类才能使用 @Bean标签作用于对应的方法上面 @Bean(destroyMethod = "destory", initMethod = "init")也可以通过这样的写法来配置bean的销毁方法和初始化方法

(3) @Component标签 👇

@Component
public class SomeBean {}
@Component
public class OtherBean {}

Spring注解创建Bean

//@Configuration标签表示这个类可被Spring识别的配置对象的类,这有有这个标记的标签的类才能使用@Bean标签作用于对应的方法上面
// @ComponentScan:开启组件自动扫描;默认情况下,它会扫描当前类所在的包及其子包中的所有标签对象加载到Spring容器
@Configuration
@ComponentScan(basePackages="com.jd.scan")
public class AppConfig {}

测试类

public class MyTest {
  @Test
  public void test() {
      ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
      SomeBean sb = ctx.getBean(SomeBean.class);
      OtherBean ob = ctx.getBean(OtherBean.class);
      System.out.println(sb);
      System.out.println(ob);
  }
}
@ComponentScan:开启组件自动扫描; 默认情况下,它会扫描当前类所在的包及其子包中的所有标签对象加载到Spring容器
  • Spring注解扩展:
    主要有四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异:
    @Component:可以用于注册所有bean
    @Repository:主要用于注册dao层的bean [@Mapper]
    @Controller:主要用于注册控制层的bean
    @Service:主要用于注册服务层的bean

三、依赖注入(DI)

控制对象与对象的关系,注入——> 设置属性

(一)三种方式:构造器、setter方法、接口注入

例子:打印机
ink 、paper是打印机printer的两个组件
用不同注入方式——都是为了给ink和paper这两个属性赋值

(1)构造器注入

Printer类

public Printer(Ink ink, Paper paper, String brand) {
  this.brand = brand;
  this.ink = ink;
  this.paper = paper;
}

application.xml

<bean id="a4Paper" class="org.lanqiao.print.A4Paper"></bean>
<bean id="blackInk" class="org.lanqiao.print.BlackInk"></bean>

<bean id="printer" class="org.lanqiao.print.Printer">
  <constructor-arg name="ink" ref="blackInk"></constructor-arg>
  <constructor-arg name="paper" ref="a4Paper"></constructor-arg>
  <constructor-arg name="brand" value="惠普"></constructor-arg>
</bean>

构造器注解注入使用注解@Autowired(对非值构造方法使用@Autowired注解)

可能有循环注入问题(类似于死锁)。 抛出BeanCurrentlyInCreationException异常表示循环依赖 → 根本原因:Spring解决循环依赖依靠的是Bean的“中间态”这个概念,而这个中间态指的是已经实例化,但还没初始化的状态。而构造器是完成实例化的东东,所以构造器的循环依赖无法解决~~~

(2) setter注入

一定要提供setter方法,才可以实现setter注入。

<bean id="printer" class="org.lanqiao.print.Printer">
  <constructor-arg name="brand" value="佳能"/>
  <property name="ink" ref="blackInk"/>
  <property name="paper" ref="a4Paper"/>
</bean>

(3)接口注入

接口注入有点复杂,被注入对象如果想要IOC容器为其注入依赖对象,就必须实现某个接口,这个接口提供一个方法,用来为被注入对象注入依赖对象,IOC容器通过接口方法将依赖对象注入到被注入对象中去。相对于前两种注入方式,接口注入比繁琐和死板,被注入对象就必须专声明和实现另外的接口

(二)两种方式:配置文件 and 注解(3)

1. @Autowired注解

Spring提供。 @Autowired(自动注入)修饰符有三个属性:Constructor,byType,byName。默认按照byType注入。 如果默认byType注入,前提条件是只能有一个实现类。
  • constructor:通过构造方法进行自动注入,spring会匹配与构造方法参数类型一致的bean进行注入,如果有一个多参数的构造方法,一个只有一个参数的构造方法,在容器中查找到多个匹配多参数构造方法的bean,那么spring会优先将bean注入到多参数的构造方法中。
  • byName:被注入bean的id名必须与set方法后半截匹配,并且id名称的第一个单词首字母必须小写,这一点与手动set注入有点不同。需要和@Qualifier注解配合使用。
  • byType:查找所有的set方法,将符合符合参数类型的bean注入。这是默认的注入方式。

2. @Resource注解

Java提供 javax.annotation.Resource这个注解同样可以实现注入功能。 @Resource注解和@Autowired有所区别的是: @AutoWried按byType自动注入,而@Resource默认按byName自动注入。
@Resource(name="a4Paper")
private Paper paper;

3. @Value注解

由于@Autowired、@Qualifier、@Resource三者自动装配只能针对于注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。因此有了@Value这个注解,@Value专门用来服务基本类型和String类型。
注意:@Value无法作用于构造方法。

四、Bean的五种作用域

正常spring框架支持两个:

  • singleton(默认)
    ——单例模式,有且只有一个实列。好处:不会频繁的进行对象创建和销毁,内存压力小。但只能在描述一个固定作用的类且大家都可以用才可以使用(打印机),不通用的对象不可以使用(筷子)。
  • prototype
    ——多例模式,需要频繁创建对象。可以用属性设置。每次请求对象不同

web项目,5个:

  • singleton:使用该属性定义Bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。
  • prototype:使用该属性定义Bean时,IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。
  • request:该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。(一次请求响应,新对象)
  • session:该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。
  • global-session:该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。

Spring默认的作用域是 :singleton

SSM仅有singleton,所有数据绑在方法的参数里

五、Bean的五种自动装配By配置文件

  1. no
    该模式表示默认情况下,不自动装配,通过“ref”attribute手动设定。
<bean id="printer" class="org.lanqiao.printer.Printer">
    <property name="ink" ref="blackInk"/>
    <property name="paper" ref="b5"/>
</bean>
<bean id="colorInk" class="org.lanqiao.printer.ColorInk"/>
<bean id="blackInk" class="org.lanqiao.printer.BlackInk"/>
<bean id="a4" class="org.lanqiao.printer.A4Paper"/>
<bean id="b5" class="org.lanqiao.printer.B5Paper"/>

  1. byName
    @Resource ——byName
    该模式表示根据Property的Name自动装配,如果一个bean的name,和另一个bean中的Property的name相同,则自动装配这个bean到Property中。当一个bean节点带有 autowire byName的属性时,将查找其类中所有的set方法名,获得将set去掉并且首字母小写的字符串,然后去spring容器中寻找是否有此字符串名称id的对象。如果有,就取出注入;如果没有,就报空指针异常。
<bean id="printer" class="org.lanqiao.printer.Printer" autowire="byName"/>
<bean id="colorInk" class="org.lanqiao.printer.ColorInk"/>
<bean id="ink" class="org.lanqiao.printer.BlackInk"/>
<bean id="a4" class="org.lanqiao.printer.A4Paper"/>
<bean id="paper" class="org.lanqiao.printer.B5Paper"/>
  1. byType
    @Autowire —— byType
    该模式表示根据Property的数据类型(Type)自动装配,Spring会总动寻找与属性类型相同的bean,若一个bean的数据类型,兼容另一个bean中Property的数据类型,则自动装配。
    注意:使用byType首先需要保证同一类型的对象,在spring容器中唯一,若不唯一会报不唯一的异常。
<bean id="printer" class="org.lanqiao.printer.Printer" autowire="byType"/>
<bean id="blackInk" class="org.lanqiao.printer.BlackInk"/>
<bean id="b5Paper" class="org.lanqiao.printer.B5Paper"/>
  1. constructor
    使用构造方法完成对象注入,其实也是根据构造方法的参数类型进行对象查找,相当于采用byType的方式。即Spring会寻找与参数数据类型相同的bean,通过构造函数将其注入。
<bean id="printer" class="org.lanqiao.printer.Printer" autowire="constructor"/>
<bean id="blackInk" class="org.lanqiao.printer.BlackInk"/>
<bean id="b5" class="org.lanqiao.printer.B5Paper"/>
  1. default
    表示默认采用上一级标签的自动装配的取值。如果存在多个配置文件的话,那么每一个配置文件的自动装配方式都是独立的。

XML 配置里的 Bean 自动装配的缺点:
1、在 Bean 配置文件里设置 autowire 属性进行自动装配将会装配 Bean 的所有属性,然而,,若只希望装配个别属性时, autowire 属性就不够灵活了。

2、autowire 属性要么根据类型自动装配, 要么根据名称自动装配, 不能两者兼而有之。

3、一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java SSMSpring+SpringMVC+MyBatis)是一种基于Java语言的Web开发框架学习这个框架的过程中,我深刻体会到它的强大和灵活性。 首先,Spring框架为开发者提供了一个强大的IOC(Inversion of Control)容器,它能够管理和注入对象,减少了代码之间的耦合性。通过配置文件或注解,我们可以轻松地定义和获取各种对象,提高了代码的可维护性和可扩展性。 其次,SpringMVC框架是一种MVC(Model-View-Controller)设计模式的实现,它用于处理Web请求和响应。通过配置一个请求映射表和处理器,我们可以将请求分发给相应的控制器进行处理,并将处理结果返回给客户端。SpringMVC还提供了一些便捷的注解和标签,用于简化页面的渲染和参数的绑定。 最后,MyBatis是一种优秀的持久化框架,它能够将数据库操作与Java对象之间的映射简化为简单的配置。通过编写SQL映射文件和定义POJO(Plain Old Java Object)类,我们可以方便地进行数据库的增删改查操作,而无需编写冗长的SQL语句。 在学习Java SSM框架的过程中,我深入理解了软件开发过程中的MVC思想,并学会了如何利用SpringSpringMVC和MyBatis来实现一个完整的Web应用程序。通过不断的实践和调试,我逐渐培养了自己解决问题和调试代码的能力。 总结起来,学习Java SSM框架使我深入理解了软件开发的各个环节,并提升了我的编码能力和开发效率。我相信这些知识和经验将对我的职业发展和项目实施起到积极的促进作用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值