Spring全场回顾-2021-7-26

本文详细介绍Spring框架的基础概念、核心组件及应用实践。包括IOC、AOP原理,事务管理,Mybatis-Spring整合等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Spring简介和优点

  • Spring是一个开源的免费的框架
  • Spring是一个轻量级的非入侵式的框架
  • 控制反转Ioc,面向切片编程AOP
  • 支持事务处理,对框架的整合的支持
  • SpringBoot是一个快速开发的脚手架
  • 基于SpringBoot可以快速才发单个微服务
  • SpringCloud协调微服务

二、Spring七大组件

  • 核心容器(Spring core)
  • Spring上下文(Spring context)
  • Spring面向切面编程(Spring AOP)
  • Spring DAO模块
  • Spring ORM模块
  • Spring Web模块
  • Spring MVC框架(Spring WebMVC)

三、IOC思想

  • 程序主动创建对象------------》程序编程被动的接收对象
  • 实现IOC的一种方式:DI。实现控制反转的是IOC容器,实现方法是依赖注入

四、第一个Spring程序

​ hello,applicationContext.xml,test

​ 所谓的IOC,一句话,对象由Spring容器来创建,管理,装配

五、继承关系和IOC执行流程和

六、IOC创建对象的方式(即通过属性赋值,属性注入,赋值完,即创建了一个对象)

  1. 使用无参构造方法创建(默认)

  2. 使用有参构造方法创建

    1. 下标赋值
    2. 类型赋值
    3. 参数名赋值(推荐)
    <bean>
    	<constructor-arg name="username" value="simon"/>
    </bean>
    

七、Spring配置文件

  • 别名

    • alias标签
    • bean中的name属性
  • bean中的scope属性,singleton,prototype

  • import标签:将多个配置文件合为一个

  • property name="" value=""/ref=""

八、依赖注入

依赖:bean对象的创建依赖于容器

注入:bean对象中的所有属性由容器来注入

  • 构造器注入(见六)
  • set方法注入(所有参数类型的注入方式,8种)
  • p/c命名空间注入

九、作用域Scope=

  • singleton/
  • prototype
  • request
  • session
  • application
  • websocket

十、自动装配(在实际开发中用得很多)

  • 一般情况,需要我们手动去Spring容器种注册Bean,即手动装配
  • Spring会在上下文中自动寻找Bean,并自动给Bean装配属性

autowired=""

  • byName:会自动在容器上下文中找,和自己全限定名路径下的set方法后面的值对应的bean的ID
  • byType:会自动在容器上下文中找,和自己对象属性(比如在people类文件中,有以下内容,即为属性),类型相同的bean的ID
public class people{
    private Cat cat;
    pricate Dog dog;
}

装配种类

  • 手动在xml种显式配置

  • Java种显式配置

  • 自动隐式装配(掌握)

  • 通过属性autowired

  • 通过注解(重要)

十一、注解开发

11.1、自动装配的注解实现

  • @Nullable 表明这个属性可以为null
  • @Autowired Required属性默认true,如果手动的设置为false,说明这个对象可以为null,否则不允许为空
  • @Qualifier(value=“dog222”)//显式的将一个属性和Ioc容器中的一个id为dog222的bean绑定
    • private Dog dog;
    • 用该注解配合@Autowired去使用
  • @Primary
  • @Resource:Java的注解,没有spring高级
    • 先通过名字去查找
    • 再通过类名去查找
    • @Resource(name=“cat1”)
    • private Cat cat;

导入注解支持(开启Ioc自动装配的注解)

<context:annotaion-config/>

<bean id="people" class="com.simon.entity.People"/>
<bean id="dog" class="com.simon.entity.Dog"/>
<bean id="cat" class="com.simon.entity.Cat"/>

@Autowired

  • 在属性上用

  • 或者在set方法上使用

public class people{
	@Autowired
    @Qualifier(value="cat333")
    private Cat cat;
    @Autowired
    @Qualifier(value="dog222")
    pricate Dog dog;
}

11.2、Spring注解开发(必须保证aop的包导入)

bean

指定要扫描的包
<context:component-scan base-package="com.simon.entity"/>
开启注解支持
<context:annotation-config/>

@Conponent

  • 添加在类名上

  • 等价于<bean id="user" class="com.simon.entity.User">

属性的注入

@Value

@Component
public class User{
    @Value("Simon")
    public String name;
}
  • 相当于

    <bean id="user" class="com.simon.entity.User">
    	<property name="name" value="Simon"/>
    </bean>
    

衍生的注解

  • @Component
    • @Repository 与@Component功能一样,都会在Spring容器中注册为一个Bean,一般用在Dao层
    • @Servcie 与@Component功能一样,都会在Spring容器中注册为一个Bean,一般用在Servcie层
    • @Controller 与@Component功能一样,都会在Spring容器中注册为一个Bean,一般用在Controller层

自动装配(见上面)

作用域

@Scope

@Scope("singleton")
public class User{
    
}

小结

  • xml更加万能,适用于任何场合

  • 注解—不是自己的类用不了,维护相对复杂,需要一个个文件的点进去查看

  • 最佳实现

    • xml用来管理bean
    • 注解只用来属性注入

使用注解,需要开启注解支持

指定要扫描的包
<context:component-scan base-package="com.simon.entity"/>
开启注解支持
<context:annotation-config/>

十二、使用Java的方式配置spring,(新特性)

  • 类似于xml配置文件的功能

  • JavaConfig以前是Spring的一个子项目

  • 这种纯Java的配置方式,在SpringBoot中随处可见

  • SpringBoot是一个脚手架,无法修改

@Configuration代表这是一个配置类,类似于xml配置文件

@Bean相当于xml配置文件中的bean标签、

  • 方法名就相当于bean标签中的id属性、

  • 方法返回值就相当于标签中的class属性

  • 方法返回值,就是返回一个对象

如果完全使用了这个JavaConfig配置类实现开发,需要使用AnnotaionConfigApplicationContext去替代ClasPathXmlApplicationContext上下文

@Configuration
@ComponentScan("包名")
@Import(AppConfig2.class)
public class AppConfig{
    @Bean
    public MyService myservice(){
        return new MyServiceImpl();
    }
}
@Component
public class MyServiceImpl{
    
}

等价于

<bean id="myService" class="com.simon.service.MyService"/>

👆

Ioc Spring容器中的类,拿出来,就是一个对象

AOP

👇

十三、代理模式

静态代理

UserService.java

package com.simon.demo1;

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void select();
}

UserServiceImpl.java

package com.simon.demo1;

public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除一个用户");
    }

    @Override
    public void update() {
        System.out.println("修改一个用户");
    }

    @Override
    public void select() {
        System.out.println("查询一个用户");
    }
}

UserServiceProxy.java

package com.simon.demo1;

public class UserServiceProxy implements UserService{
    private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }

    @Override
    public void update() {
        log("update");
        userService.update();
    }

    @Override
    public void select() {
        log("select");
        userService.select();
    }

    public void log(String msg){
        System.out.println("使用了"+msg+"方法");
    }
}

Client.java

package com.simon.demo1;

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();

        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(userService);

        proxy.add();
    }
}

动态代理

Proxy类和InvocationHandler类

Rent.java

package com.simon.demo2;

public interface Rent {
    public void rent();
}

Host.java

package com.simon.demo2;

public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东要出租房子");
    }
}

ProxyInvocationHandler.java

package com.simon.demo2;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }

    //生成的到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this);
    }

    @Override
    //处理代理实例,并且返回处理结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        seeHouse();
        //动态代理的实质,就是通过反射机制实现
        Object result = method.invoke(rent, args);
        fee();
        return result;
    }

    public void seeHouse(){
        System.out.println("中介带你看房子");
    }
    public void fee(){
        System.out.println("收中介费fee");
    }
}

Client.java

package com.simon.demo2;

public class Client {
    public static void main(String[] args) {
        //真实角色
        Host host = new Host();
        ProxyInvocationHandler pih = new ProxyInvocationHandler();

        //通过调用程序处理角色  来处理我们将要调用的接口对象
        pih.setRent(host);
        Rent proxy = (Rent) pih.getProxy();//这里的Proxy就是动态生成的代理类
        proxy.rent();
    }
}


ProxyInvocationHandler.java

package com.simon.demo03;

import com.simon.demo2.Rent;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成的到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }

    @Override
    //处理代理实例,并且返回处理结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //动态代理的实质,就是通过反射机制实现
        Object result = method.invoke(target, args);

        return result;
    }
}

Client.java

package com.simon.demo03;

import com.simon.demo1.UserService;
import com.simon.demo1.UserServiceImpl;

public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();

        ProxyInvocationHandler pih = new ProxyInvocationHandler();

        //设置要代理的对象
        pih.setTarget(userService);

        //动态生成代理类
        UserService proxy = (UserService)pih.getProxy();

        proxy.add();
    }
}

十四、AOP的三种实现方式

UserService.java

package com.simon.service;

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void select();

}

UserServiceImpl.java

package com.simon.service;

public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
        System.out.println("修改了一个用户");
    }

    @Override
    public void select() {
        System.out.println("查找了一个用户");
    }
}

applicationContext.xml

<bean id="userService" class="com.simon.service.UserServiceImpl"/>
    <bean id="log" class="com.simon.log.Log"/>
    <bean id="afterLog" class="com.simon.log.AfterLog"/>

方法一:

  • 使用原生Spring API接口

  • 配置aop:需要导入aop的约束

AfterLog.java

package com.simon.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);
    }
}

Log.java

package com.simon.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"执行了");
    }
}
<aop:config>
    <!--切入点,expression: 表达式,execution(要执行的位置)-->
    <aop:pointcut id="pointcut" expression="execution(* com.simon.service.UserServiceImpl.*(..))"/>
    <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>

方法二—自定义类,DIY类

DiyPintCut.java

package com.simon.diy;

public class DiyPointCut {
    public void before(){
        System.out.println("============方法执行前==========");
    }
    public void after(){
        System.out.println("============方法执行hou==========");
    }
}

applicationContext.xml

<bean id="diy" class="com.simon.diy.DiyPointCut"/>
<aop:config>
    <!--自定义切面,即切入点-->
    <aop:aspect ref="diy">
        <!--自定义切面-->
        <aop:pointcut id="point" expression="execution(* com.simon.service.UserServiceImpl.*(..))"/>
        <!--通知方法-->
        <aop:before method="before" pointcut-ref="point"/>
        <aop:after method="after" pointcut-ref="point"/>
    </aop:aspect>
</aop:config>

方法三—通过注解的方法

AnnotationPointCut.java

package com.simon.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect//标注这个类是一个切面
public class AnnotationPointCut {

    @Before("execution(* com.simon.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("============方法执行前==========");
    }
    @After("execution(* com.simon.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("============方法执行hou==========");
    }

    @Around("execution(* com.simon.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {

        System.out.println("====环绕前==========");
        System.out.println(jp.getSignature());//获得签名

        //执行方法
        Object proceed = jp.proceed();

        System.out.println("后");
    }
}

applicationContext.xml

<bean id="annotationPointCut" class="com.simon.diy.AnnotationPointCut"/>
<!--也可以不在这里用标签注册,
        在类名上添加一个@Component即可完成注册
    -->
<!--开启注解支持-->
<aop:aspectj-autoproxy/>

    <!--DateSource:Spring的数据源替换Mybatis的配置 c3p0 dbcp druid
        我们这里使用Spring提供的JDBC: org.springframework.jdbc.datesource
    -->
    <bean id="dateSource" class="org.springframework.jdbc.datesource.DriverManagerDateSource">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property  name="driver" value="jdbc:mysql:http://localhost:3306/testdb:"/>
        <property  name="username" value="root"/>
        <property  name="password" value="root"/>
    </bean>
    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dateSource" ref="dateSource"/>
        <!--绑定mybatis配置文件-->
        <property name="configuration" value="classpath:mybatis-config.xml"/>
    </bean>
    <!--SqlSessionFactoryTemplate就是我们的SqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能通过构造器注入sqlSessionFactory 因为底层源码没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

十四、Mybatis-Spring的整合

创建mapper和sqlSession并且注入到bean中

mybatis3.5+

spring5+

还有一个mybatis-spring2.0+

方法一、SqlSessionTemplate

要使mybatis和spring一起使用,最少需要导入两个东西

,一个sqlSessionFactory和是少一个数据映射类

在mybatis-Spring中,可以使用SqlSessionFactoryBean来创建SqlSessionFactory。而要配置这个bean只需要把以下代码放入Spring的xml文件中

注意:SqlSessionFactory 需要一个 DataSource(数据源)

 <!--SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!--dataSource 使用spring-jdbc替换mybatis的配置,类似的还有c3p0,dbcp,druid,-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property  name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&amp;useSSL=false&amp;characterEncoding=utf-8"/>
        <property  name="username" value="root"/>
        <property  name="password" value="root"/>
    </bean>


    <!--就是我们使用的SqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能用构造器注入,sqlSessionFactory,没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
public class UserDaoImpl implements UserDao {

  private SqlSession sqlSession;

  public void setSqlSession(SqlSession sqlSession) {
    this.sqlSession = sqlSession;
  }

  public User getUser(String userId) {
    return sqlSession.selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
  }
}

<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
  <property name="sqlSession" ref="sqlSession" />
</bean>

写一个UserDao实现类UserDaoImpl,把sqlSession私有化,然后在Spring容器中注册UserDaoImpl,并且把sqlSessionTemplate注入到实现类中去

方法二、SqlSessionDaoSupport

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
  public User getUser(String userId) {
    return getSqlSession().selectOne("com.simon.dao.UserMapper.getUser", userId);
  }
}

调用 getSqlSession() 方法你会得到一个 SqlSessionTemplate,之后可以用于执行 SQL 方法

<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

需要注入一个sqlSessionFactory,因为父类需要注入一个会话工厂

如果这样是实现了,就不需要在Spring容器中注册SqlSessionTemplate了

十五、事务(待完善)

事务Transaction

事务的ACID原则

  • 原子性
  • 一致性
  • 隔离性
    • 多个业务可能操作同一个资源
  • 持久性
    • 事务一旦提交,无论系统发生什么

原本应该是spring的事务。

MyBatis-Spring 允许 MyBatis 参与到 Spring 的事务管理中。

而不是给 MyBatis 创建一个新的专用事务管理器,

MyBatis-Spring 借助了 Spring 中的 DataSourceTransactionManager 来实现事务管理。

一旦配置好了 Spring 的事务管理器,你就可以在 Spring 中按你平时的方式来配置事务。

并且支持 @Transactional 注解和 AOP 风格的配置。

在事务处理期间,一个单独的 SqlSession 对象将会被创建和使用。

当事务完成时,这个 session 会以合适的方式提交或回滚。

事务配置好了以后,MyBatis-Spring 将会透明地管理事务。

这样在你的 DAO 类中就不需要额外的代码了。

标准配置

要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 DataSourceTransactionManager 对象:

需要一个数据源

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <constructor-arg ref="dataSource" />
</bean>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tc:attributes>
        <tx:method name="*" propaganda="REQUIRED"/>
    </tc:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="txPointCut" expression="execution(* com.simon.dao.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>

声明式事务:在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。底层采用AOP思想来实现的。

编程式事务:需要在代码中进行事务的管理

public class UserService {
  private final PlatformTransactionManager transactionManager;
  public UserService(PlatformTransactionManager transactionManager) {
    this.transactionManager = transactionManager;
  }
  public void createUser() {
    TransactionStatus txStatus =
        transactionManager.getTransaction(new DefaultTransactionDefinition());
    try {
      userMapper.insertUser(user);
    } catch (Exception e) {
      transactionManager.rollback(txStatus);
      throw e;
    }
    transactionManager.commit(txStatus);
  }
}

声明式事务控制明确事项:

核心业务代码(目标对象) (切入点是谁?)

事务增强代码(Spring已提供事务管理器))(通知是谁?)

切面配置(切面如何配置?)

十六、总结

拓展(ApplicationContext对象的来源)

  • ApplicationContext
  • 👆继承
  • ConfigurableApplicationContext
  • 👆实现接口
  • AbstractApplicationContext
  • 👆继承
  • AbstractRefreshableApplicationContext
  • 👆继承
  • AbstractRefreshableConfigApplicationContext
  • 👆继承
  • AbstractXmlApplicationContext
  • 👆继承继承
  • ClassPathXmlApplicationContext
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

荆北彭于晏

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

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

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

打赏作者

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

抵扣说明:

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

余额充值