Spring从入门到精通

第一章 Spring基础

1.环境搭建

导入Pom

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>

附属下载的内容
在这里插入图片描述

2. 配置文件

1、配置文件的放置位置:任意位置即可。
2、配置文件的命名:没有硬性要求,建议为applicationContext.xml

注意在以后的编码过程中,需要对配置文件路径进行设置

2.1.配置文件创建

在这里插入图片描述

3. Spring的核心API

3.1 applicationContext

  • ApplicationContext
    作用:Spring提供的ApplicationContext这个工厂,用于对象的创建
    好处:解耦合
  • ApplicationContext为接口类型
接口的作用:屏蔽实现的差异
非web环境:ClassPathXmlApplicationContext(main方法中,或者junit)
   web环境:XmlWebApplicationContext

非web环境在这里插入图片描述
在这里插入图片描述

3.2 applicationContext

ApplicationContext工厂的对象占用大量的内存
不会频繁创建对象,一个应用之后创建一个工厂对象。
applicationContext这种工厂一定是线程安全的。

4.Spring第一个程序

步骤:

1、创建类型
2、配置文件的配置 applicationContext.xml
   <!--id起个名字,唯一;class配置全限定名-->
    <bean id="person" class="com.xiaohe.Person"></bean>

3、通过工厂类,获取对象

    @Test
    public void test(){
        //获取Spring工厂
        /**
         * ClassPathXmlApplicationContext参数表示配置文件的路径
         * */
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("/applicationContext.xml");

        //根据工厂获取对象
        /**
         * getBean参数表示配置文件bean下的id名字
         * */
        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person);
    }

}

细节分析

  • 名称解释

Spring工厂创建的对象,叫做bean或者组件(Compont)

  • spring工厂相关的方法
 @Test
    public void test1(){
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        //Person person=applicationContext.getBean("person",Person.class);
        //System.out.println(person);

        //当前Spring配置文件中,只能有一个<bean class是Person类型>
       Person person=applicationContext.getBean(Person.class);
        System.out.println(person);

       //获取的是Spring工厂配置文件所有配置的ID值
       String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println("beanDefinitionNames="+beanDefinitionName);
        }

      //根据类型获取spring工厂配置文件的id值
     String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
        for (String s : beanNamesForType) {
            System.out.println("--->"+s);
        }

       //用于判断配置文件是否存在指定id值的bean
       boolean isExist = applicationContext.containsBeanDefinition("person");
        System.out.println(isExist);
      
        //用于判断配置文件是否存在指定id值的bean
        boolean isExist= applicationContext.containsBean("person");
        System.out.println(isExist);
      
    }

spring配置文件需要注意的细节

在spring配置文件中只写class,不写id

  <bean class="com.xiaohe.Person"/>

测试

@Test
  public void test2(){
      //创建ApplicationContext对象
      ApplicationContext applicationContext=new ClassPathXmlApplicationContext("/applicationContext.xml");
      /*Person bean = applicationContext.getBean(Person.class);
      System.out.println("--->"+bean);*/
      String[] beans = applicationContext.getBeanDefinitionNames();
      for (String bean : beans) {
          System.out.println("----》"+bean);
      }

  }

结果
在这里插入图片描述

Spring配置文件的name属性

作用:用于在spring的配置文件中,为bean对象定义别名
id与name(别名)的相同点与不同点
相同:
1、applicationContext.getBean(“id/name”);
2、<bean name="" class="" 等效于<bean name="" class=""
不同:
1、别名可以定义多个,中间用逗号隔开
2、xml 的id属性值命名时要求:必须要以id开头,name属性的值,命名没有要求。

5.spring工厂的底层原理(简易版)

在这里插入图片描述

第二章 spring与日志框架的整合

spring与日志框架的整合,日志可以在控制台进行打印,输出一些重要的信息。
默认:spring默认整合logback,log4j2

Spring整合log4j过程
1、引入log4j jar包
2、引入log4j.properties配置文件

  • 引入pom文件
 <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.25</version>
    </dependency>
    
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
  • log4j.properties
# resources # resources⽂件夹根⽬录下
### 配置根
log4j.rootLogger =debug,console
### ⽇志输出到控制台显示
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-ddHH:mm:ss} %-5p %c{1}:%L - %m%n

第三章 注入

1.什么是注入

通过Spring工厂及配置文件,为所创建的对象的成员变量赋值。

1.1为什么要注入

在这里插入图片描述

1.2如何进行注入

  • 1.类为成员变量提供set/get方法
  • 2.配置spring的配置文件
  <bean id="person" name="p" class="com.xiaohe.Person" >
        <property name="name">
            <value>和振斌</value>
        </property>
        <property name="age">
        <value>20</value>
        </property>
    </bean>
  • 测试
  /**
   * 测试注入
   * */
  @Test
  public void test5(){
      ApplicationContext applicationContext=new ClassPathXmlApplicationContext("/applicationContext.xml");
      Person person = (Person) applicationContext.getBean("person");
      System.out.println("person:"+person);
  }

1.3注入的好处

解耦合

1.4Spring注入原理分析(简易版)

在这里插入图片描述
Set注入和构造注入
在这里插入图片描述

第三章 控制反转与依赖注入

1、控制反转(IOC)

1、控制:对于成员变量赋值的控制权
2、反转控制:把对于成员变量赋值的控制权,从代码中反转到spring工厂和配置文件中去。
3、底层实现:工厂设计模式

实现图
在这里插入图片描述

依赖注入(Dependency Injection DI)

注入:通过Spring的工厂及其配置文件,为对象的成员变量赋值

依赖注入:当一个类需要另一个类时,就意味着依赖,一旦出现依赖,就可以把另一个类作为本类的成员变量,最终通过Spring配置文件进行注入
好处:解构

在这里插入图片描述
在这里插入图片描述

2、Spring工厂创建复杂对象的三种方式

步骤

  • 1、实现FactoryBean接口
    在这里插入图片描述
public class ConnectionFactory implements FactoryBean<Connection> {
    //用于书写创建复杂对象的代码
    public Connection getObject() throws Exception {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123456");

        return conn;
    }

    public Class<?> getObjectType() {
        return Connection.class;
    }

    public boolean isSingleton() {
        return false;
    }
}
  • 2、Spring配置文件的配置
<bean id="conn" class="com.xiaohe.factoryBean.ConnectionFactory"/>

2.2、实例工厂

1、避免spring的侵入
2、整合遗留问题

开发步骤

<bean id="connFactory"class="com.baizhiedu.factorybean.ConnectionFactory"></bean>
<bean id="conn" factorybean="connFactory"factorymethod="getConnection"/>

实例工厂

    <bean id="conn" class="com.xiaohe.factoryBean.ConnectionFactory" factory-method="getConnection"/>

1.3Spring工厂总结

在这里插入图片描述

第四章 控制Spring工厂创建对象的次数

1、简单工厂创建次数

<bean id="accont" scope="singleton | prototype" class="xxx.Account"
singleton:只创建一次
prototype:创建多次

2、为什么要控制对象的创建次数
好处:节省内存

生命周期

在这里插入图片描述

第五章 后置处理Bean

1、BeanPostProcessor作用:对于Spring工厂所创建的对象,进行再加工
在这里插入图片描述

我们实现BeanPostProcessor规定的接口的方法
Object postProcessBeforeInitiallization(Object bean,String beanName)
作用:Spring在创建完对象,并进行注入后,可以运行Before方法进行加工
获得Spring创建好的对象,通过方法的参数
最终通过返回值交给Spring框架


Object postProcessAfterInitallization(Object bean,Strinng beanName)
作用:Spring在执行完对象的初始化操作后,可以运行After方法进行加工
获得Spring创建好的对象,通过方法的参数
最终通过返回值交给Spring框架
  • BeanPostProcessor开发步骤
    1、类实现BeanPostProcessor接口
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
      public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
          System.out.println("实现了postProcessBeforeInitialization");
          return bean;
      }
    
      public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
           Categroy categroy= (Categroy) bean;
           categroy.setName("hzb cool");
          return categroy;
      }
    
    • spring配置文件配置
        <bean id="c" class="com.xiaohe.BeanPost.Categroy">
            <property name="id" value="10"/>
            <property name="name" value="hzb"/>
        </bean>

    <bean id="myBeanPostProcessor" class="com.xiaohe.BeanPost.MyBeanPostProcessor"/>

运行效果
在这里插入图片描述

  • 注意BeanPostProcessor会对工厂所有对象进行加工。

第六章 AOP编程

1、静态代理设计模式

为什么需要代理设计模式?

在这里插入图片描述

2、代理设计模式

2.1 概念

通过代理类,为原始类增加额外的功能
好处:利于原始类的维护

2.2 编码

静态代理:为每一个原始类,手工编写一个类

public class UserServiceProxy implements UserService {
    //原始对象
    private UserServiceImpl userService=new UserServiceImpl();
    public void register(User user) {
        System.out.println("日志的额外功能");
        userService.register(user);
    }

    public boolean login(String name, String password) {
        System.out.println("日志的额外功能");
        return userService.login(name,password);
    }
}

2.3 静态代理存在的问题

1、静态类文件数量过多,不利于项目管理
UserServiceImpl ----------UserServiceProxy
OrderServiceImpl---------OrderServiceProxy
2、额外功能维护性差

3、Spring的动态代理

3.1 概念

通过动态代理类为原始类增加额外功能

3.2搭建环境

导入pom


    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.2.1.RELEASE</version>
    </dependency>


    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.9.5</version>
    </dependency>

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

3.3 开发步骤

1.第一步:创建原始对象

public class UserServiceImpl implements UserService {
    public void register(User user) {

        System.out.println("执行业务运算+DAO");
    }

    public boolean login(String name, String password) {
        System.out.println("执行了登录方法");
        return false;
    }
}

第二步:创建userService对象

<bean id="userService" class="com.xiaohe.proxy.OrderServiceImpl"/>

额外功能开发 Spring提供了MethodBeforceAdvice接口
第三步: 额外功能

public class Before implements MethodBeforeAdvice {

    /**
     * 作用: 需要运行在原始方法执行之前运行额外功能,书写在before方法中
     * */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("----method before advice log");
    }
}
<bean id="before" class="com.xiaohe.dynamic.Before"/>

第四步:定义切入点

切入点:额外功能加入的位置
目的:由程序员根据自己需求,决定额外功能加入给哪个原始方法

第五步 简单的测试:让所有的文件
在配置里面写

<aop:config>
           <!--切入点-->
            <!--expression切入点表达式 表示所有的方法都是切入点-->
           <aop:pointcut id="pc" expression="execution(* *(..))"/>
  </aop:config>

组装

<!--组装-->
           <aop:advisor advice-ref="before" pointcut-ref="pc"/>

调用

目的:获取Spring工厂创建的动态代理的对象,并进行调用
注意
1、Spring的工厂通过原始对象的id值获得的是代理对象
ctx.getBean(“userService”);
2、获得的代理对象后,可以通过声明接口类型,进行对象的存储

4、动态代理的好处

好处一、
在额外功能不改变的过程中,创建其他目标类的对象时,只需要指定原始对象即可。
在这里插入图片描述
好处二、
动态代理额外功能的维护性大大增强。

5、动态代理详解

四步骤
在这里插入图片描述

5.1、Spring动态代理详解

  • MethodBeforeAdvice分析
    1、MethodBeforeAdvice接口的作用:额外功能运行在原始方法之前,进行额外功能操作。
public class Before implements MethodBeforeAdvice {

    /**
     * 作用: 需要运行在原始方法执行之前运行额外功能,书写在before方法中
     * method表示:额外功能所增加给的那个原始方法
     * Object[]:额外功能增加给那个原始方法的参数
     * Object:原始对象
     * */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("----method before advice log");
    }
}

2、Before方法的三个参数在实战中,该如何使用:
before方法的参数,在实战中,会根据需要进行使用,不一定都会用到,也可能用不到。

  • MethodInterceptor(方法拦截器)
/**
 * 拦截器
 * invoke方法的作用:额外功能写在invoke
 *                  额外方法 原始方法之前
 *                           原始方法之后
 *                           原始方法之前 之后
 *   参数:MethodInvocation 表示额外功能所增加的那个原始方法
 * */
public class Arround implements MethodInterceptor {

    public Object invoke(MethodInvocation invocation) throws Throwable {

        System.out.println("------前--------");
        //原始方法运行
        Object ret = invocation.proceed();

        System.out.println("------后---------");
        return ret;
    }
}

MethodBeforeAdvice只能运行在原始方法之前

5.2、切入点详解

<aop:pointcut id="pc" expression="execution(* *(..))"/>

切入点表达式:
execution()切入点函数
* *(…)
在这里插入图片描述
第一个 *表示修饰符和返回值
第二个 *表示方法名
第三个 …表示参数
精准方法切入点表示方法
在这里插入图片描述
execution()切入点函数

1、最为重要的切入点函数,功能最全
2、执行方法切入点表达式类切入点表达式包切入点函数

弊端:书写麻烦

args

作用:主要用于函数方法参数的匹配
切入点:方法参数必须是两个字符串类型的参数

within

主要用于进行类、包切入点表达式的匹配
切入点:UserServiceImpl这个类
execution(* *.userServiceImpl.*(..))
within(*..UserServiceImpl)

posted @ 2020-11-09 22:01  池三岁  阅读(361)  评论(0编辑  收藏  举报