入门级-SSM框架(Spring篇)

Spring

Spring IOC(控制反正)和DI(依赖注入)是什么?

IOC (Inverse of Control)控制反转:

  • 曾经:
    静态依赖:类中的依赖的对象是通过New关键字在堆中创建对象并被引用进行依赖对象调用方法
    动态依赖:通过反射,获取依赖对象类的Class对象,创建实例并依赖对象实例调用方法
  • 现在:
    将依赖的对象交给Spring IOC容器中统一管理,需要依赖某个对象时通过IOC容器依赖注入到对应的类中
    ,那么这么一来依赖的对象控制权在第三方的手中。可能是xml配置文件、可能是JavaBean注解开发

DI (Dependency Injection) 依赖注入:

  • 基于控制反转思想进行实现,对底层原生代码进行封装提供了对应的API,将需要依赖的对象剥离到Spring IOC容器中管理的类通过Spring API进行注入到需要依赖的位置

IOC和DI的关系

  • IOC控制反转的抽象思想将对象进行管理,DI是注入的具体实现行为。IOC和DI互相搭档,实现了降低解耦。

DI让对象和对象依赖的功能实现,而对象在IOC中进行统一管理,所以依赖的功能需要基于IOC容器为DI提供数据Bean对象

  • 曾经:

多态关系进行赋值依赖,类中维护对象之间的依赖关系。若发生变动,当需要修改依赖子为实现B时,需要修改代码,重构系统应用
在这里插入图片描述

  • 现在:

通过resource外部文件IOC容器维护类依赖关系。若依赖关系发生变动,无需修改java代码,仅修resource配置文件
在这里插入图片描述

使用前不得不知道的知识点?

如何从java目录中读取resource目录中的IOC容器?

在这里插入图片描述

Bean的作用范围(既多次获取是否是同一个地址值对象)
[默认模式:单例模式]
<bean  id="" class="" scope="singleton">
[其他模式:原型模式] 每次获取都创建新的地址值对象
<bean  id="" class="" scope="prototype">
生命周期方法如何触发执行任务?(销毁方法触发需要执行特定的方法,否则无法执行)
  1. 自己配置触发执行
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
    //表示bean初始化对应的操作
    public void init(){
        System.out.println("init...");
    }
    //表示bean销毁前对应的操作
    public void destory(){
        System.out.println("destory...");
    }
}
<bean  id="" class="" init-method="绑定类中方法名" destroy-method="绑定类中方法名">
  1. 通过实现规范触发执行
public class Main implements InitializingBean, DisposableBean {
   
	@Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("service destroy");
    }
}
[实现规范] 即可简单配置
<bean  id="" class="">

解决销毁方法无法执行的问题,原因是因为JVM退出后,IOC容器没有来得及关闭

  • 手工关闭容器
    ConfigurableApplicationContext接口close()操作
  • 注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机
    ConfigurableApplicationContext接口registerShutdownHook()操作

Spring实例化和依赖注入的方式分别有什么?

在这里插入图片描述

Spring实现实例化的四种方式(即管理对象,仅创建对象,并不初始化成员变量)
  1. 构造器实例化Bean : 使用无参或无参
[无参实例化]
<bean id="user" class="con.xy.pojo.User"/>

[有参实例化] 需要额外加入构造依赖注入:分为1.name形参名匹配 2.type类型匹配 3.index索引匹配(0开始)
<bean id="user" class="con.xy.pojo.User">
        <constructor-arg ref="需要引用IOC中的Bean•setter方法后属性名"/>
        <constructor-arg name="基本类型成员变量•setter方法后属性名" value="赋值"/>
</bean>

注解型
类@Component @Controller @Service @Reposity
范围@Scope(“singleton”)

  1. 静态工厂方式实例化Bean:
[静态工厂]随着类的加载而加载,即类名可以直接调用静态方法。无需对工厂产品进行注册Bean
<bean id="user•将会返回产品实例" class="con.xy.utils.UserStaticFactory" factory-method="getUser•拥有返回工厂产品的静态方法名"/>

注解型
方法返回值@Bean

  1. 实例工厂方法实例化Bean:
[实例工厂]顾名思义,需要实例化获取工厂对象,才能调用getter方法获取产品,分两步。无需对工厂产品注册Bean
<bean id="实例化工厂" class="con.xy.utils.UserInstanceFactory" />
<bean id="user•将会返回产品实例" factory-method="getUser•拥有返回工厂产品的实例方法名" factory-bean="引用IOC容器中实例化的工厂Bean"/>

注解型
方法返回值@Bean

  1. 通用Spring工厂实例化Bean:
[步骤一 java目录:继承springFrameWork的工厂规范接口]
class UserInstanceFactory implements FactoryBean<T•工厂产生的商品类型•用接口可以多态多样产品>
[步骤二 resource目录:Spring规范通用工厂]
<bean id="user" class="con.xy.utils.UserFactory"/>
依赖注入的四种方式(即实例化对象,又成员初始化赋值)
  1. 构造方法注入使用此方式需要注入形参所有的属性
[有参构造器注入] 无参构造器注入个辣子🌶️,无需考虑

- 形参名 匹配注入
<bean id="" class="">
    <constructor-arg name="" value="基本类型"/>
    <constructor-arg name="" ref="引用类型•需要关联IOC容器中其他Bean的id"/>                  
</bean>

- 形参类型 匹配注入
<bean id="" class="">
    <constructor-arg type="" value="基本类型"/>
    <constructor-arg type="" ref="引用类型•需要关联IOC容器中其他Bean的id"/>
</bean>

- 形参索引 匹配注入
<bean id="" class="">
    <constructor-arg index="" value="基本类型"/>
    <constructor-arg index="" ref="引用类型•需要关联IOC容器中其他Bean的id"/>
	
	<constructor-arg>
		<array value-type="数组类型">
    		<value></value>
    		<value></value>
    		<value></value>
		</array>
	</constructor-arg>	
	
	<constructor-arg>
		<list value-type="arrayList集合类型">
    		<value></value>
    		<value></value>
    		<value></value>
		</list>
	</constructor-arg>
	
	<constructor-arg>
		<set value-type="hashSet集合类型">
    		<value></value>
    		<value></value>
	    	<value></value>
		</set>
	</constructor-arg>
	
	<constructor-arg>
		<map key-type="hashMap集合类型" value-type="">
    		<entry key="" value=""/>
    		<entry key="" value=""/>
    		<entry key="" value=""/>
		</map>
	</constructor-arg>
	
	<constructor-arg>
		<props value-type="properties配置集合">
    		<prop key=""></prop>
	  		<prop key=""></prop>
    		<prop key=""></prop>
		</props>
	</constructor-arg>
</bean>
  1. Setter方法注入 (设值注入) 可选的依赖关系,但需要提供无参构造或者无参的静态工厂方法创建对象集合数组Proerties注入仅与构造constructor-arg不同,可以传入多个相同集合不同属性名,推荐使用Setter方式注入,因为灵活
[Setter方法注入] 灵活优于构造器注入,可以对部分成员不进行初始化
<bean id="" class="">
    <property name="Setter方法后的属性名•首字母变小写" value="基本类型的值"/>
    <property name="Setter方法后的属性名•首字母变小写" ref="引用类型•需要关联IOC容器中其他Bean的id"/>
    
	<property name="array">
  	  <array>
      	 <value>100</value>
       	 <value>200</value>
      	 <value>300</value>
  	  </array>
	</property>    
	
	<property name="list">
    	<list>
    	    <value>itcast</value>
	        <value>itheima</value>
        	<value>boxuegu</value>
        	<value>chuanzhihui</value>
    	</list>
	</property>

	<property name="set">
    	<set>
        	<value>itcast</value>
        	<value>itheima</value>
        	<value>boxuegu</value>
   		 </set>
	</property>

	<property name="map">
    	<map>
       	 	<entry key="country" value="china"/>
      		 <entry key="province" value="henan"/>
      		 <entry key="city" value="kaifeng"/>
   		 </map>
	</property>

	<property name="properties">
    	<props>
        	<prop key="country">china</prop>
        	<prop key="province">henan</prop>
        	<prop key="city">kaifeng</prop>
    	</props>
	</property>
</bean>
  1. 自动装配注入基于Setter方法
[自动装配注入] 自动从IOC容器中匹配其他Bean进行填充
- 类型自动注入:务必保证IOC中Bean的Type唯一性
<bean id="" class="" autowire="byType"/>

- 属性名自动注入: 务必保证IOC中Bean的id名符合Setter后属性名
<bean id="" class="" autowire="byName"/>
  1. 注解注入

@Autowired :按照类型注入 [ 组合@Qualifier 按照名称装配 ]

@Value: 普通类型注入 或 读取properties 配置文件 “${}” 无需Setter

@Resource :
指定名称name和类型type会进行唯一匹配,找不到则抛出异常
指定仅名称name,按照名称(id)匹配Bean进行装配,找不到抛出异常
指定名称type,按照类型匹配Bean进行装配,找不到抛出异常
不进行任何指定,自动按照优先byName方式进行匹配,无法匹配尝试进行type匹配

容器类
配置@Coinfiguration + 扫描目录下Bean @Component(多目录1,多目录2) + @Import(获取子容器1,获取子容器2)
属性配置读取 @PropertySource(“classpath:jdbc.properties”)

测试类(pom依赖容易发生不兼容问题)
spring测试启动器
@RunWith(SpringJUnit4ClassRunner.class)
获取java容器
@ContextConfiguration(classes = {SpringConfiguration.class})


Data Access/Integration (数据 访问/一体化) (简化与第三方框架整合)

【1.Dependency依赖准备】在这里插入图片描述

	<properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>


        <dependencies>
            <!--     核心Spring框架       -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>

            <!--      第三方框架: mybatis      -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.6</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>1.3.0</version>
            </dependency>

            <!--      第三方框架: Mysql Jdbc      -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.25</version>
            </dependency>
            <!--      第三方框架: DataSource数据源      -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.16</version>
            </dependency>
             <!--      第三方框架: DataSource数据源     -->
            <dependency>
   				 <groupId>c3p0</groupId>
    			 <artifactId>c3p0</artifactId>
   				 <version>0.9.1.2</version>
			</dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>

            <!--      第三方框架: Junit测试      -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>

            <!--      第三方框架: AOP切面织入     -->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.7</version>
            </dependency>
        </dependencies>

【2.配置Bean】在这里插入图片描述
【解决应配置问题】(多属性配置文件可合并) 在这里插入图片描述

【3.创建容器】

//类路径加载单个配置文件(常规)
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//类路径加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("context_1.xml", "context_2.xml");

//文件路径加载配置文件(绝对路径)
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\applicationContext.xml");

//类路径加载配置文件(java目录下)
Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resources);

//注解式类配置容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

Spring AOP(面向切面编程)(非入侵式,不需要修改原处代码即可对功能增强)

切面织入依赖
<!--      第三方框架: AOP切面织入     -->
<dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.7</version>
</dependency>
核心概念

连接点(JoinPoint) 被增强的方法
切入点(Pointcut) 增强的代理方法
通知(Advice) 对增强方法的执行时机
通知类 定义多个通知时机
切面(Aspect) 执行的过程 或 是对应关系

通知类 @Aspect 标记为切面类

容器类 @EnableAspectJAutoProxy 配置开启

切入点 @PointCut(execution(public * com.itheima..UserService.find()))
任意单词*
execution(public * com.itheima.
.UserService.find*(*))
多级路径..

executio\n(public User com…UserService.findById(…))
子级匹配+
execution(* *…Service+.(…))

为什么使用AOP?
  1. 降低耦合度
  2. 侵略性小,避免了修改代码
  3. 复用性高,制定增强的代码对切入点进行注入
AOP如何使用?用到了什么地方?

前置通知:@Before
后置通知:@After
返回后通知:@AfterReturning 类似于finlly
异常通知:@AfterThrowing 仅发生异常
环绕通知:@Around 前置+后置混合+异常捕捉+返回后通知

日志处理(执行次数追踪,性能监测,异常记录)
事务处理(对增删改这类操作进行事务管理)


事务管理

配置类开启事务管理
@EnableTransactionManagement
事务传播级别(业务处理层)
@Transactional(propagation = Propagation.REQUIRES_NEW,readOnly=true)

什么是动态代理?动态代理都有哪些?

不修改代码的情况下,对代码进行增强,使用时字节码随用随创建,随用随加载

  • 基于接口的动态代理,要求:被代理类最少实现一个接口
提供者:JDK官方,涉及类:Proxy
创建代理对象方法:newProxyInstance
涉及到创建对象方法里的参数:ClassLoader:类加载器【固定写法】
负责加载代理对象使用的字节码,需要和被代理对象使用相同类加载器:
Class[]:字节码数组【固定写法】
负责让生成的代理对象具有和被代理对象相同的方法。
写什么要看被代理对象是一个接口还是一个实现类
如果是一个接口:new Class[]{接口}
如果是一个实现类:XXX.getClass().getInterfaces()
InvocationHandler:一个接口,需要我们提高该接口的实现,写的是一个接口的实现类
增强代码,谁用写谁,通常是匿名内部类,不是绝对的
  • 基于子类的动态代理,要求:需要导入第三方cglib的坐标依赖。
提供者:Cglib第三方,涉及类:Enhancer
创建代理对象的方法:create
方法的参数:
Class: 字节码对象,用于加载代理对象字节码,写的是被代理对象的字节码
Callback:如何代理。提供增强代码。
(它是个接口,需要实现这个接口没有的方法,需要使用它的子接口 MethodInterceptor)
动态代理使用场景
  1. 基于AOP思想的方法增强
  2. 自动以连接池中,实现Connection的cloase方法将连接还回池中的操作,可以使用动态代理或装饰者模式
  3. 解决全站中文乱码,get和post两种提交方式
    在get方式需要对一下三个方法增强,用于解决乱码
    (tomcat8.5底层解决)
    String value= getParameter(String name);
    String[]value=getParameterValues(String name);
    Map<String,String[]>map = getParameterMa();
什么是静态代理?
JDK动态代理 与 CGLIB动态代理的区别?

相同点:

  • 均属于Spring AOP技术动态代理的实现方式

不同点:

  • jdk动态代理:通过反射接收被代理的类,核心InvocationHandler和Proxy类
    缺点:被代理类必须实现接口,也就是说被代理的类必须有接口的实现关系

  • cglib动态代理:适用于没有实现接口的类,cglib是一个代码生成类库,运行阶段动态生成某个类的子类(目标类),cglib通过继承的方式动态代理
    缺点:类将需要能够被继承,不能被标记为final,那么无法cglib动态代理

<!--配置平台事务管理器-->
<!--注入连接池-->


<!--配置切面类(Aspenct):TransactionDefiniton设置方法-->
<!--
    read-only:是否只读事务,默认false
    isolation:指定隔离级别
    propagation:指定事务的传播行为
    timeout:超时时间,默认-1永不超时
    rollback-for:用于指定异常,当异常出发时,被指定的异常事务回滚
    no-rollback-for:用于指定异常,当异常出发时,被指定的异常事务不回滚
-->

<!--声明AOP-->
<!--配置切入点指定事务服务的包以及织入id-->
<!--织入id指定切面类-->

Bean的作用域

  • singleton(默认:单例模式)IOC仅创建一个Bean实例,每次返回同一个实例
    生命周期与容器同长
  • prorotype(原型[多例]模式)IOC创建多个实例,每次返回一个新的实例
    生命周期使用完被垃圾回收
  • request(Http请求)每次HTTP请求都会创建一个新的Bean,使用WebApplicatonContext
  • session(当前会话)一个Session共享一个Bean,不同Session使用不同的实例

Spring事务声明

不考虑事务隔离性引发的安全问题?

  • 脏读: 读取到其他事务未提交回滚的数据
  • 不可重复读: 事务需要重复读一些数据,但没有执行完时,读取到其他事务操作后的数据,导致重复读取的数据不一致
  • 幻读: 事务执行时,其他事务执行修改的数据符合当前逻辑,导致当前事务查询多次结果不一致

事务的隔离界别

  • read uncommited读未提交: 三种安全问题都会发生
  • read commited只读已提交: 重复读 幻读
  • repeatable read可重读读: 幻读
  • serializable串行化: 三种安全问题都被解决

隔离界级别越高,安全性高,效率越低

Spring如何管理事务?

  • 编程式事务管理: Spring推荐使用TransactionTemplate工具类(但是开发中声明式事务使用较多)
    缺点:
    1.事务管理的代码和业务代码将会同时出现,分层不明确
    2.使用工具类进行类与类的依赖,耦合性强
  • 声明式事务管理: 利用AOP面向切面编程思想,选择目标,对目标进行环绕时拦截。在方法目标执行前加入或创建一个事务,在方法执行后,根据情况选择提交或是回滚事务.
    优点:
  1. 业务代码与事务分离,事务部分统一在Spring的xml配置文件中集中管理
  2. 降低耦合性

Spring的事务管理器有什么?
Spring不会直接管理事务,对其他多平台提供的事务管理器接口,事务管理器充当一个工具类,从而用户在Spring使用事务,不要用关心事务的实现
Spring的事务只读是强制的吗?
选择只读Spring将会对查询的方法进行性能优化
对于事务需要设置多长超时时间?
事务的执行时间不能过长,如果超时需要记录保存日志

项目中如何实现使用Spring事务?

Spring提供三个接口,事务需要这三个的实现共同执行

  • PlatFormTransactionManager
    commit 事务提交
    rollback 事务回滚
    getTransaction 获取事务
  • TRansactonDefinition
    getIsonlationLevel:获取隔离级别
    getPropagetionBehavior:获取传播行为
    getTimeout获取超时时间
    isReadOnly是否只读(false可读写,true只读)
  • TransactionStatus
    hasSavepoint返回事务内部是否包含一个保存点
    isComplated返回事务是否已经完成提交或回滚
    isNewTransaction判断是否是一个新事物

Spring中用到哪些设计者模式?

  1. 工厂模式BeanFactory以及ApplciationContext
  2. 模板模式BeanFactory以及ApplciationContext
  3. 代理模式AOP的JDK动态代理
  4. 单例模式创建Bean的时候
  5. 策略模式JdbcTmplate通过SQL获取数据,但获取数据的分组类型
    RowMapper接口以及BeanPropertyRowMapper的是实现类
    RowMapper接口定义规范,而实现类提供不同的策略
  6. 观察者模式 WebApplciatonContext,是通过ContextLoaderListener监听器实现创建的.监听器就是观察者模式的具体实现 (事件源 时间 监听者)
  7. 适配器模式
    @Controller注解
    实现Controller接口
    实现HttpRequestHandler接口
    8.装饰者模式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值