学习完Mybatis框架进而学习完Spring框架的总结

发布于:2022-12-21 ⋅ 阅读:(156) ⋅ 点赞:(0)

        一名在读大学的学生,跟着黑马程序员学完了Spring框架,对其过程做了上万字的笔记,做笔记也是为了巩固已学的知识,希望这份笔记能够解决大家的一点疑惑。

目录

一、Spring

一、基本概述

二、框架划分图

二、Spring IOC

一、核心概念

二、目标:充分解耦

三、快速入门

四、bean作用范围说明

五、bean生命周期

六、依赖自动装配

七、依赖自动装配特征

八、创建容器

九、获取bean

十、容器相关接口

十一、bean标签相关的属性

三、注解开发定义bean 纯注解开发

一、注解开发定义bean

二、纯注解开发

三、bean作用范围与生命周期管理

四、注解开发依赖注入

五、第三方bean依赖注入

六、Spring结合Mybatis

七、Spring结合JUnit

四、Spring AOP

一、核心概念

二、AOP入门案例分析

三、AOP切入点表达式

四、AOP通知类型

五、环绕通知中获取签名对象及参数

六、AOP通知获取数据

七、JDK动态代理和CGLIB动态代理的区别


一、Spring

一、基本概述

Spring是一个IOC和AOP的容器框架、并且是开源的,是为了简化企业开发而产生的,使得开发变得更加优雅和简洁。

二、框架划分图

蓝色框表示独立具体的模块黑色框表示需要的依赖

模块解释:
   Test:Spring的单元测试模块
   Core Container:核心容器模块
   AOP+Aspects:面向切面编程模块
   Instrumentation:提供了class instrumentation支持和类加载器的实现来在特定的应用服务器上使用,几乎不用
   Messaging:包括一系列的用来映射消息到方法的注解,几乎不用
   Data Access/Integration:数据的获取/整合模块,包括了JDBC,ORM,OXM,JMS和事务模块
   Web:提供面向web整合特性

二、Spring IOC

一、核心概念

1、IOC(Inverison of Control) 控制反转 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。

  • 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的

  • 反转 : 程序本身不创建对象 , 而变成被动的接收对象 。

2、Spring技术对IOC思想进行了实现

        ①Spring提供了一个容器,称为IOC容器,用来充当IOC思想的"外部" 。

        ②IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IOC容器中统称为Bean。

3、DI(Dependency Injection) 依赖注入是控制反转的一种方法 在容器中建立bean和bean之间的依赖关系的整个过程,称为依赖注入。

二、目标:充分解耦

1、使用IOC容器管理bean(IOC)

2、在IOC容器内将有依赖关系的bean进行关系绑定(DI)

3、最终效果:使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定所有的依赖关系。

三、快速入门

步骤1、在pom.xml中导入Spring坐标

2、定义Spring管理的类(接口)

3、创建Spring配置文件,配置对应类作为Spring管理的bean。定义的id属性同一个上下文不能重复

4、初始化IOC容器,通过容器获取bean

四、bean作用范围说明

为什么bean默认为单例?

①适合交给容器进行管理的bean:表现层、业务层、数据层、工具对象

②不适合交给容器进行管理的bean:封装实体的域对象

五、bean生命周期

1、bean生命周期:bean从创建到销毁的整体过程,以下两个关闭IOC容器的方法 ①ClassPathXmlApplicationContext.close();手工关闭 ②ClassPathXmlApplicationContext.registerShutdownHook();注册关闭钩子,JVM退出前关闭

2、bean生命周期控制:在bean创建后到销毁前做一些事情

<bean init-method="" destory-method="" />  提供生命周期控制方法

实现InitializingBean、DisposableBean接口

生命周期:

1、初始化容器:①创建对象(内存分配)、②执行构造方法、③执行属性注入(set操作)、④执行bean初始化方法

2、使用bean:执行业务操作

3、关闭销毁容器

六、依赖自动装配

1、IOC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配

2、自动装配方式(autowire=""):按类型(常用)、按名称、按构造方法、不启动自动装配

七、依赖自动装配特征

1、自动装配用于引用类型依赖注入,不能对简单类型进行操作

2、使用按类型分配时(byType)必须保障容器中相同类型的bean唯一,推荐使用

3、使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐

4、自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

八、创建容器

        Spring容器是Spring的核心,一切Spring bean都存储在Spring容器内,并由其通过IOC技术管理。Spring容器也就是一个bean工厂(BeanFactory)。应用中bean的实例化、获取、销毁等都是由这个bean工厂管理的。通过以下三种方式可以显示的初始化一个容器:

1、类路径加载配置文件:ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

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

3、加载多个配置文件:ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");

九、获取bean

1、使用bean名称获取:BeanDao beanDao = (BeanDao) ctx.getBean("beanDao");

2、使用bean名称获取并指定类型:BeanDao beanDao = ctx.getBean("beanDao",BeanDao.class);

3、使用bean类型获取:BeanDao beanDao = ctx.getBean(BeanDao.class);

通过:Resource resources = new ClassPathResource("applicationContext.xml");
     BeanFactory bf = new XmlBeanFactory(resources);初始化bean延迟加载,不会执行无参构造
或通过:ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");初始化bean会立即加载

十、容器相关接口

1、BeanFactory是IOC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载

2、ApplicationContext接口是Spring容器的核心接口,初始化bean会立即加载

3、ApplicationContext接口提供基本的bean操作相关方法,通过其他接口扩展其功能

4、ApplicationContext接口常用初始化类 :

①ClassPathXMLApplicationContext ②FileSystemXmlApplicationContext

十一、bean标签相关的属性

1、id="bookDao" bean的ID

2、neam="a b c" bean的别名

3、class="com.chf.dao.impl.bookDaoImpl" bean类型、静态工厂类、FactoryBean类

4、scope="singleton" 控制bean的实例数量

5、init-method="init" 生命周期的初始化方法

6、destory-method="destory" 生命周期销毁方法

7、autowire="byType" 自动装配类型

8、factory-method="getInstance" bean工厂方法,应用于静态工厂或实例工厂

9、factory-bean="com.chf.factory.BookDaoFactory" 实例工厂bean

10、lazy-init="true" 控制bean延迟加载 

三、注解开发定义bean 纯注解开发

一、注解开发定义bean

Spring提供@Component注解的三个衍生注解

① @Controller:用于表现层bean定义

② @Service:用于业务层bean定义

③ @Repository:用于数据层bean定义 注解后面可以不写(""),默认id是类名首字母小写。

二、纯注解开发

1、Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道

@Configuration                                       用于设定当前类为配置类
@ComponentScan({"com.chf.service","com.chf.dao"})    用于设定扫描路径,只能添加一次
public class SpringConfig{}

2、读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象 ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

三、bean作用范围与生命周期管理

1、在类上使用注解@Scope定义bean作用范围。

@Scope("singleton")单例;@Scope("prototype")非单例

2、在方法上添加注解@PostConstruct即是bean的初始化

3、在方法上添加注解@PreDestory即是bean的销毁时刻

四、注解开发依赖注入

1、在属性上添加注解@Autowired可以省略构造属性的set方法

2、使用@Qualifier注解开启指定名称装配bean。必须配合@Autowired注解使用

3、使用@Value实现简单类型注入:@Value("");@Value("${}")可以引用外部资源的内容但是需要在SpringConfig的类上使用注解@PropertySource("classpath:jdbc.properties"),不支持通配符"*"

五、第三方bean依赖注入

public class JdbcConfig {
    //1.定义一个方法获得要管理的对象
    @Value("com.mysql.cj.jdbc.Driver")
    private String driver;
    @Value("jdbc:mysql://localhost:3306/ssm")
    private String url;
    @Value("root")
    private String userName;
    @Value("root")
    private String password;
    //2.添加@Bean,表示当前方法的返回值是一个bean
    //@Bean修饰的方法,形参根据类型自动装配
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }
}
@Configuration
//@Import:导入配置信息
@Import({JdbcConfig.class})
public class SpringConfig {
}

2、引用类型依赖注入

注意:引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象

@Bean
public DataSource dataSource(BookService bookService){
    System.out.println(bookService);
    DruidDataSource ds = new DruidDataSource();
    ds.setDriverClassName(driver);
    ds.setUrl(url);
    ds.setUsername(userName);
    ds.setPassword(password);
    return ds;
}
@Configuration
@ComponentScan("com.chf.service")
@Import({classpath:JdbcConfig.class})
public class SpringConfig {
}

六、Spring结合Mybatis

1、首先在pom.xml文件中添加以下配置

<!--Spring结合JDBC-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
  <version>5.2.10.RELEASE</version>
</dependency>

<!--Spring结合Mybatis-->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>1.3.0</version>
</dependency>

2、在resources目录下去写jdbc.properties的配置文件

jdbc.driver=com.mysql.cj.jbdc.driver
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=root

3、在config目录下创建JdbcConfig类

public class JdbcConfig {
    //1.定义一个方法获得要管理的对象
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String userName;
    @Value("${jdbc.password}")
    private String password;
    
    @Bean
    public DataSource dataSource(DataSource dataSources){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }
}

4、将Mybatis中的SqlMapConfig核心配置文件进行了优化修改

public class MybatisConfig {
    //定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setTypeAliasesPackage("com.chf.pojo");//代替的是注册实体类别名<typeAliases></typeAliases>中的<package>
        sqlSessionFactoryBean.setDataSource(dataSource);//代替的是数据源配置中的			<environments>
        return sqlSessionFactoryBean;
    }
    //定义bean,返回MapperScannerConfigurer对象
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();//代替的是注册mapper文件<mapper></mapper>
        msc.setBasePackage("com.chf.dao");//代替的是批量注册<package>
        return msc;
    }
}

七、Spring结合JUnit

1、首先在pom.xml中添加以下配置

<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>

2、在Test-Java下创建测试类

//设置类运行器
@RunWith(SpringJUnit4ClassRunner.class)
//设置类Spring环境对应的配置
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
    //支持自动装配注入bean
    @Autowired
    private AccountService accountService;

    @Test
    public void testFindById(){
        System.out.println(accountService.findById(1));
    }

    @Test
    public void testFindAll(){
        System.out.println(accountService.findAll());
    }
}

四、Spring AOP

一、核心概念

AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构。

OOP(Object Oriented Programming)面向对象编程

        作用:在不惊动原始设计的基础上为其进行功能增强。减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。

Spring理念:无入侵式/无侵入式

核心原理:观察所调用的方法是否符合切入点表达式,如果符合,则使用代理执行增强方法。

①连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等。

在SpringAOP中,理解为方法的执行。

②切入点(Pointcut):匹配连接点的式子。

在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法:

一个具体方法:com.chf.dao包下的BookDao接口中的无形参无返回值的save方法。

匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口的任意方法,所有带有一个参数的方法。

③通知(Advice):在切入点处执行的操作,也就是共性功能。包含五种类型:前置、后置、环绕、返回后、抛出异常后通知。

在SpringAOP中,功能最终以方法的形式呈现。

④通知类:定义通知的类。

⑤切面(Aspect):描述通知与切入点的对应关系,只关注点模块化。

⑥目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的。

⑦代理(Proxy):核心本质。目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现。

二、AOP入门案例分析

1、导入坐标(pom.xml)

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.4</version>
</dependency>

2、制作连接点方法(原始操作,Dao接口与实现类)

public interface BookDao {
    void save();

    void update();
}

@Repository
public class BookDaoImpl implements BookDao {

    public void save() {
        System.out.println(System.currentTimeMillis());
        System.out.println("book dao save");
    }

    public void update(){
        System.out.println("book dao update ...");
    }
}

3、制作共性功能(通知类与通知):新建一个aop包新建MyAdvice的类

public class MyAdrice{
	public void before(){
		System.out.println(System.currentTimeMillis());
	}
}

4、定义切入点表达式

说明:切入点定义依托一个不具有实际意义的方法进行,即无参数、无返回值、方法体无实际逻辑。

public class MyAdrice{
	@Pointcut("execution(void com.chf.dao.BookDao.update())")
	public class pt(){}
}

5、绑定切入点与通知关系(切面)

public class MyAdrice{
	@Pointcut("execution(void com.chf.dao.BookDao.update())")
	public class pt(){}
	
	@Before("pt()")
	public void before(){
		System.out.println(System.currentTimeMillis());
	}
}

6、定义通知类受Spring容器管理,并定义当前类为切面类

//1、先用注解@Component使此类变为可以被Spring控制的bean
@Component
//2、再用注解@Aspect告诉Spring此类为切面,需要读取其中的注解方法
@Aspect
public class MyAdrice{
	@Pointcut("execution(void com.chf.dao.BookDao.update())")
	public class pt(){}
	
	@Before("pt()")
	public void before(){
		System.out.println(System.currentTimeMillis());
	}
}

7、在配置类当中开启Spring对AOP注解驱动支持

@Configuration
@ComponentScan("com.chf")
//3、最后用注解@EnableAspectJAutoProxy为了执行切面的注解方法
@EnableAspectJAutoProxy
public class SpringConfig {
}

三、AOP切入点表达式

1、切入点:要进行增强的方法。

2、切入点表达式:要进行增强的方法的描述方式。

描述方式一:执行com.chf.dao包下的BookDao接口中的无参数update方法

execution(void com.chf.dao.BookDao.update())

描述方式二:执行com.chf.dao.impl包下的BookDaoImpl类中的无参数update方法

execution(void com.chf.dao.impl.BookDaoImpl.update())

3、切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)

①动作关键字:描述切入点的行为动作,例如execution表示执行到指定切入点

②访问修饰符:public、private等可以省略

③异常名:方法定义中抛出指定异常,可以省略

4、可以使用通配符描述切入点,快速描述

①*:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现。常用

 ②..:多个连续的任意符号,可以独立出现,常用于简化包名与参数的手写。常用

execution(public User com..UserService.findById(..))

匹配com包下的任意包中的UserService类或接口中所有名称为findById的方法。

③+:专用于匹配子类类型

四、AOP通知类型

1、AOP同时描述的抽取的共性功能,根据共性功能抽取的位置不同,最终运行时要将其加入到合理的位置。

2、AOP通知共分为5种类型:

①前置通知:@Before

②后置通知:@After

③环绕通知(重点):@Around

这个方法会将想要切入的方法直接取代,只会输出两句话。

@Around("pt()")
public void around(){
	System.out.println("around before advice");
	System.out.println("around after advice");
}

需要再形参中添加ProceedingJoinPoint就可以对原先方法进行环绕。

对原始方法的调用可以不接收返回值,通知方法设置为void即可,如果接收返回值,必须设定为Object类型。

原始方法的返回值如果是void类型,通知方法的返回值类型可以设置为boid,也可以设置为Object。

由于无法预知原始方法运行后是否抛出异常,因此环绕通知方法必须抛出Throwable对象。

@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
	System.out.println("around before advice");
    Object o = pjp.proceed();//表示对原始操作的调用
	System.out.println("around after advice");
    return o;
}

④返回后通知(了解):@AfterReturning

⑤抛出异常后通知(了解):@AfterThrowing。被此注解注解的类在抛出异常后才会运行。

五、环绕通知中获取签名对象及参数

//设置环绕通知,在原始操作的运行前后记录执行时间
@Around("ProjectAdvice.servicePt()")
public void runSpeed(ProceedingJoinPoint pjp) throws Throwable {
    //获取执行的签名对象
    Signature signature = pjp.getSignature();
    //通过签名获取执行类型(接口名)
    String className = signature.getDeclaringTypeName();
    //通过前面获取执行操作名称(方法名)
    String methodName = signature.getName();

    long start = System.currentTimeMillis();
    for (int i = 0; i < 10000; i++) {
       pjp.proceed();
    }
    long end = System.currentTimeMillis();
    System.out.println("万次执行:"+ className+"."+methodName+"---->" +(end-start) + "ms");
}

六、AOP通知获取数据

1、获取切入点方法的参数

        ①JoinPoint:适用于前置、后置、返回后、抛出异常后通知

@Before("pt()")
public void before(JoinPoint jp){
	Object[] args = jp.getArgs();
	System.out.println(Arrays.toString(args));
}

        ②ProceedJoinPoint:适用于环绕通知

注:以下的Object[] getArgs()为获取连接点方法运行时的入参列表;

@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
	Object[] args = jp.getArgs();
	System.out.println(Arrays.toString(args));
    Object ret = pjp.proceed(args);
    return ret;
}

2、获取切入点方法返回值

        ①返回后通知

@AfterReturning(value="pt()",returning="ret")
public void afterReturning(String ret){
	System.out.println("afterReturning advice"+ret);
}

        ②环绕通知

@Around("pt()")
public Object arount(ProceedingJoinPoint pjp) throws Throwable{
	Object ret = pjp.proceed();
	return ret;
}

3、获取切入点方法运行异常信息

        ①抛出异常后通知

@AfterThrowing(value="pt()",throwing="t")
public void afterThrowing(Throwable t){
	System.out.println("afterThrowing advice"+t);
}

        ②环绕通知

@Around("pt()")
public Object around(ProceedingJoinPoint){
	Object ret = null;
	try{
		ret = pjp.proceed();
	} catch(Throwable t){
		t.printStackTrace();
	}
	return ret;
}

七、JDK动态代理和CGLIB动态代理的区别

        JDK动态代理只提供接口的代理,不支持类的代理,该代理类是实现了目标类接口, 并且代理类会实现接口所有的方法增强代码。调用时通过代理类先去调用处理类进行增强,再通过反射的方式进行调用目标方法。从而实现AOP。如果代理类没有实现接口,那么Spring AOP会选择使用。       

        CGLIB来动态代理目标类。 ​ CGLIB在运行时动态的生成目标类的一个子类。并且会重写父类所有的方法增强代码,调用时先通过代理类进行增强,再直接调用父类对应的方法进行调用目标方法。从而实现AOP。

简单来说就是:JDK动态代理需要被代理类必须实现接口,CGLIB不需要。

本文含有隐藏内容,请 开通VIP 后查看