SpringReview(黑马)

Spring:轻量级,非入侵式的IOC容器管理工具

主学spring framework

spring这个框架利用IOC和AOP的编程思想,帮我们做对象的创建,管理和装配.

  • 根本作用:所有对象不用new了
  • 根本重点:IOC(对象控制权反转)和AOP(面向切面编程)
  1. spring的根本是在interface21框架上发展而来的.一步步发展出一个个的spring framework(spring框架)

  2. Spring是一个概念,springmvc,springboot等都属于Spring家族,都是一个个的spring framework

spring-webmvc依赖集成了如spring-core,spring-web等基本spring framework

在这里插入图片描述


核心内容:IOC对象控制权反转

DI是进行IOC容器内对象的赋值操作的

IOC对象控制权反转是一种编程思想

  1. DI(依赖注入,也可以理解为对象属性自动赋值)只是实现IOC的一种方式,其他的还有如XML文件,注解的实现IOC的方式

  2. IOC容器根本目的是让代码类之间解耦,所有人都去IOC容器中找自己需要的资源

在这里插入图片描述

<!--这个beans就是IOC容器,在这里面定义的所有东西都会放在IOC容器中-->
<beans xmlns="http://www.springframework.org/schema/beans"
</beans>

惰性加载

  • 实体类的构造函数中输出一句话,用Application加载beans.xml,就会执行输出语句

  • 而用BeanFactory就不会.

Application的顶级父类是BeanFactory,这是spring1.0时的容器创建对象.

它在创建对象时是惰性加载,实际就是单例设计模式的懒汉模式

<!--开启惰性加载-->
<bean lazy-init="true"/>

这里我们只运行这一行,就不会运行输出语句了

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

注解开发

定义bean

@Component("student")
public class Student {

全注解开发,去掉配置文件

//把配置文件剩下的东西变成下面这个类
@Configuration
@ComponentScan("pojo")
public class SpringConfig {
}

//改变获取spring容器的方式为注解配置类获取
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);

bean管理

@Component("student")
@Scope("prototype")
public class Student {

  @PostConstruct
  public void init(){
    System.out.println("初始化");
  }
  
  @PreDestroy
  public void destroy(){
    System.out.println("销毁前");
  }
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);

Student student = context.getBean("student", Student.class);

//如果是@Scope("singleton"),会调用destroy()
context.close();

自动装配

@Autowired//byType自动装配
@Qualifier("student2")//byName自动装配
private Student student;


//或者
@Autowired
@Qualifier("student1")
public void setStudent(Student student){
  this.student = student;
}

简单类型自动注入

//配置类上加
@PropertySource("1.properties")//不支持通配符
public class SpringConfig {
@Value("${name}")
private String name;

管理第三方的bean

@Configuration
public class jdbcConfig {

  @Bean
  public DataSource dataSource(){
    DruidDataSource dataSource = new DruidDataSource();

    dataSource.setUsername("root");

    return dataSource;

  }
}


//主config扫描副config所有的包  
@ComponentScan("pojo")
public class SpringConfig {}
  
//或者直接导入  
@Import({jdbcConfig.class})
public class SpringConfig {  
spring扫描包智能注入所需bean
@ComponentScan("pojo")
public class SpringConfig {}

//只要Student在pojo包下,即使不写@aotuwried,spring会智能帮我们注入进去
@Bean
public DataSource dataSource(Student student){

整合Mybatis

mybatis只管理sqlSessionFactroy对象,因为无论你业务怎么变化,对于数据库的基本连接是不会变的.而spirng管理的是业务面.

基本环境

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.6</version>
</dependency>

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.28</version>
</dependency>


<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.12</version>
  <scope>provided</scope>
</dependency>


<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.3.18</version>
</dependency>

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.2.8</version>
</dependency>

driver=com.mysql.cj.jdbc.Driver
username=root
password=root
url=jdbc:mysql:///springreview?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <properties resource="jdbc.properties"></properties>

    <typeAliases>
        <package name="domain"/>
    </typeAliases>

    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="jdbc"></transactionManager>
          	<!--pooled是利用了连接池的思想,其他还有unPooled-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${password}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <package name="dao"/>
    </mappers>

</configuration>

UserDao

package dao;

import domain.Student;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface UserDao {


  //没有实现类,用自动代理来接收值
  //Mybatis会用自动代理的形式,扫描配置文件,创建对应的实现类
  @Select("select * from student where id = #{id}")
  List<Student> findById(Integer id);


}

实体类

package domain;


import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class Student {

  private Integer id;

  private String name;
  private Integer age;


}
import dao.UserDao;
import domain.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;

public class Test {

  public static void main(String[] args) {

    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    try {
      InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");

      SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);

      SqlSession sqlSession = build.openSession();

      UserDao mapper = sqlSession.getMapper(UserDao.class);
      List<Student> byId = mapper.findById(2);

      Iterator<Student> iterator = byId.iterator();

      while (iterator.hasNext()){
        Student next = iterator.next();
        System.out.println(next);

      }


    } catch (IOException e) {
      e.printStackTrace();
    }


  }

}

整合mybatis

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>2.0.6</version>
</dependency>

<!--spring操作数据库-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
  <version>5.3.19</version>
</dependency>

配置DataSource

package com.itCast.configs;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class jdbcConfig {

  @Bean
  public DataSource dataSource(){
    DruidDataSource dataSource = new DruidDataSource();

    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setPassword("root");
    dataSource.setUrl("jdbc:mysql:///springreview?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC");
    dataSource.setUsername("root");

    return dataSource;
  }

}

将mybatis-config.xml替换成配置类

package com.itCast.configs;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;

public class MybatisConfig {

  @Bean//Spring快速构建SqlSessionFactory的对象
  public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){

    SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(dataSource);
    sqlSessionFactoryBean.setTypeAliasesPackage("com.itCast.domain");

    return sqlSessionFactoryBean;

  }

  //spring-jdbc依赖中有jdbc的事务管理,不用配置
  @Bean
  public MapperScannerConfigurer mapperScannerConfigurer(){
    MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
    mapperScannerConfigurer.setBasePackage("com.itCast.dao");
    return mapperScannerConfigurer;
  }


}

主配置类融合所有副配置类

package com.itCast.configs;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;

@Configuration
@ComponentScan("com.itCast")
@Import({jdbcConfig.class,MybatisConfig.class})
@PropertySource("jdbc.properties")
public class SpringConfig {}
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);

UserDao bean = context.getBean(UserDao.class);

List<Student> byId = bean.findById(2);

整合junit

<!--单元测试-->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>
  <scope>test</scope>
</dependency>

<!--Spring框架用来做单元测试的工具。使用SpringTest需要结合Junit一起使用-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>5.3.14</version>
</dependency>
package com.itCast;

import com.itCast.configs.SpringConfig;
import com.itCast.dao.UserDao;
import com.itCast.domain.Student;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.Iterator;
import java.util.List;

//运行器:让junit4运行于spirng测试环境
@RunWith(SpringJUnit4ClassRunner.class)
//指定上下文配置类,还可以指定配置文件
@ContextConfiguration(classes = SpringConfig.class)
public class Test {


  @Autowired
  private UserDao userDao;

  @org.junit.Test
  public void test() {
    List<Student> byId = userDao.findById(2);

    Iterator<Student> iterator = byId.iterator();

  }

}

Aop面向切面编程

在这里插入图片描述

在这里插入图片描述

<!--spring-webmvc默认导入了spring-aop依赖-->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.8.RC1</version>
</dependency>

定义通知类

package com.itCast.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect//标明这是一个通知类
public class MyAop {

    //执行,筛选方法:没有返回值的对应类路径下的对应参数列表的方法,执行时都被定义成切入点
    @Pointcut("execution(* com.itCast.dao.UserDao.findById(Integer))")
    private void point(){}

    //定义通知
    @Before("point()")
    public void aspect(){
        System.out.println("这是一个通知");
    }

}
@EnableAspectJAutoProxy//开启自动代理通知
public class SpringConfig {}

工作流程

spirng只读取被切面配置了的切入点

spirng如果通知和切入点匹配成功,会创建原始对象(目标对象)的代理对象.

然后用代理对象来执行操作.

spring的aop的本质是代理模式

System.out.println(userDao);
System.out.println(userDao.getClass());

//执行结果
org.apache.ibatis.binding.MapperProxy@146587a2
class com.sun.proxy.$Proxy31

切入点表达式

在这里插入图片描述

*是必须有,…可以为0

在这里插入图片描述

通知类型

//环绕通知
@Around("point()")
public Object aspect(ProceedingJoinPoint joinPoint) throws Throwable {
  
  //获取当前连接点签名
  Signature signature = point.getSignature();
  //连接点名字 = 方法名
  String name = signature.getName();
  
  System.out.println("通知前");

  Object proceed = joinPoint.proceed();

  System.out.println("通知后" + name);

  return proceed;
}


//方法运行结束后织入
@AfterReturning("execution(* com.itCast.dao.UserDao.findById(Integer))")
public void aspect(){
  System.out.println("方法运行结束后织入");
}


//方法出现异常后织入
@AfterThrowing("execution(* com.itCast.dao.UserDao.findById(Integer))")
public void aspect(){
  System.out.println("方法出现异常后织入");
}

获取aop通知的数据

@Before("point()")
public void aspect(JoinPoint joinPoint){
  //获取连接点参数
  Object[] args = joinPoint.getArgs();

  System.out.println("参数列表是"+ Arrays.toString(args));
}

@Around("point()")
public Object aspect(ProceedingJoinPoint joinPoint) throws Throwable {

  Object[] args = joinPoint.getArgs();

  //修改连接点参数
  args[0] = 100;
  
  //把新的参数给连接点进行
  Object proceed = joinPoint.proceed(args);

  System.out.println("这是一个通知");

  return proceed;
}


@AfterReturning(value = "point()",returning = "ret")
//point对象必须在第一个,ret是获取连接点的返回值
public void aspect(JoinPoint joinPoint, Object ret){
  System.out.println("返回值是"+ret);
}


@AfterThrowing(value = "point()",throwing = "ret")
//获取异常信息
public void aspect(Throwable ret){
  System.out.println("异常信息是"+ret);
}

案例:数据兼容处理

@Around("point()")
public Object aspect(ProceedingJoinPoint joinPoint) throws Throwable {

  Object[] args = joinPoint.getArgs();

  for (int i = 0; i < args.length; i++) {
    //如果是字符串,去空格
    if(args[i].getClass().equals(String.class)){
      args[i] = args[i].toString().trim();
    }
  }

  //原方法执行后把返回值交给了我们,我们需要最后再给他返回出去
  return joinPoint.proceed(args);
}

Spirng事务

spirng事务是可以在业务层上加的,实现业务层调用的数据层方法同成功同失败

基本的转账业务

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;

@Repository
public interface UserDao {

  //@Param("money")给形参命名,到时sql语句可对应自动匹配
  @Update("update student set money = money-#{money} where id = #{id}")
  void outMoney(@Param("id")Integer id,@Param("money") Double money);

  //每个增删改操作都有自己单独的事务,如果后面的操作出问题,前面的操作不会改变事务
  @Update("update student set money = money+#{money} where id = #{id}")
  void inMoney(@Param("id")Integer id,@Param("money") Double money);

}

开启spring事务

@EnableTransactionManagement//开启spring事务管理
public class SpringConfig {}

jdbcConfig配置Spring平台事务管理器

//Spring的平台事务管理器允许你在业务层进行事务管理
@Bean//@Transactional需要有一个TransactionManager的bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource){

  //spring使用jdbc的事务管理,需要一个数据源
  // Mybatis默认使用的是jdbc的事务,以后要变直接改这里
  DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();

  dataSourceTransactionManager.setDataSource(dataSource);

  return dataSourceTransactionManager;
}

业务层配置事务属性

import org.springframework.transaction.annotation.Transactional;

@Transactional//使成员拥有spring事务属性,可以写在方法上.
public interface UserService {

  void money(int outId,int inId,Double money);

}
package com.itCast.service.impl;

import com.itCast.dao.UserDao;
import com.itCast.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    public void money(int outId, int inId, Double money) {
        userDao.outMoney(outId,money);

      	//出现异常,测试事务
        int i = 1/0;
        userDao.inMoney(inId,money);
    }

}

Spring事务角色

Spring的事务管理员(事务发起方)是一个事务,将**方法中的所有其他事务(事务协调员)**方法(事务加入方)加入自己的事务,实现同成功同失败.

在这里插入图片描述

Spring事务属性

//mysql事务默认只对error和运行时异常生效
@Transactional(rollbackFor = {IOException.class})

//只读事务,永不超时
@Transactional(readOnly = true,timeout = -1)

Spring事务传播行为

设置事务协调员对于事务管理员的态度

//自己单独成为一个事务,不加入事务管理员,不被同成功同失败
@Transactional(propagation = Propagation.REQUIRES_NEW)
void LogService(Integer outId,Integer inId,Double money);
//测试
try {
  userDao.outMoney(outId,money);

  int i = 1/0;
  userDao.inMoney(inId,money);
}finally {
  logService.LogService(outId,inId,money);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

helloses

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

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

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

打赏作者

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

抵扣说明:

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

余额充值