Spring

一、简介

  1. Spring轻量级,开源javaEE框架
  2. 简化开发
  3. 两大核心部分:IOC,AOP
    • IOC:控制反转:把创建对象的过程交给Spring进行管理
      (1)IOC底层原理
      (2)IOC接口(BeanFactory)
      (3)IOC操作Bean管理(基于xml)
      (4)IOC操作Bean管理(基于注解)
    • AOP:面向切面编程:在不修改源代码的情况下,进行功能增加或增强
  4. 特点:
    • 方便解耦,简化开发
    • Aop
    • 方便程序测试
    • 方便集成其他框架
    • 降低API使用难度
    • 方便事务操作

二、IOC

1.什么是IOC


(1)控制反转,把对象的创建和对象之间的调用过程交给Spring进行管理
(2)使用IOC的目的,是为了降低耦合

2.IOC底层原理


(1)xml解析、工厂模式、反射

  1. 工厂模式:[https://www.runoob.com/design-pattern/factory-pattern.html](https://www.runoob.com/design-pattern/factory-pattern.html)
  2. xml解析:
  3. 反射:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/12737431/1630029278315-ba778832-04f0-40a3-9490-1922fd50cfe0.png#clientId=u1c189b18-4bdf-4&from=paste&height=292&id=ue46102e1&margin=%5Bobject%20Object%5D&name=image.png&originHeight=584&originWidth=1295&originalType=binary&ratio=1&size=274756&status=done&style=none&taskId=ue43cd717-7d21-4767-b1c0-50ff61d9d19&width=647.5)

3.IOC接口(接口)

(1)IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
(2)Spring提供IOC容器实现的两种方式(两个接口):
BeanFactory:是IOC容器基本实现,内部使用接口,一般不提供开发人员使用
*加载配置文件时不会创建对象,在获取对象时才创建。

ApplicationContext:BeanFactory接口的子接口,提供更多更强大功能,由开发人员使用
*加载配置文件时就会创建对象
(3)ApplicationContext实现类
image.png

4.IOC操作Bean管理

  1. 什么是Bean管理

Spring创建对象
Spring注入属性

  1. Bean管理操作的两种方式

基于xml文件
基于注解

  1. 基于XML方式
    1. 基于XML方式创建对象

<bean id="user" class="com.study.spring5.User"></bean>
在spring配置文件中使用bean标签
bean标签属性:
id:唯一标识
class:创建的类的全路径(包+类)
name:早期属性,相当于id,用于struts1

  - 创建对象时默认执行无参构造方法,**所以必须有无参构造方法**
  2. 基于XML方式注入属性
  - DI:依赖注入,就是注入属性

第一种方式:set方法

     - 创建类,属性及其set方法
     - 在spring配置文件中配置对象的创建,配置属性注入
    <bean id="book" class="com.atguigu.spring5.Book">
        <property name="bname" value="大耳朵图图"></property>
        <property name="author" value="胡英俊"></property>
    </bean>

第二种方式:构造方法

     - 创建类,以及有属性的参数构造方法
    <bean id="orders" class="com.atguigu.spring5.Orders">
        <constructor-arg name="oname" value="胡图图"></constructor-arg>
        <constructor-arg name="address" value="幸福社区幸福街幸福花园1201号"></constructor-arg>
    </bean>

5.p名称空间注入(了解)

简化set方法注入

  1. 添加p名称空间在配置文件中

image.png

  1. 属性注入

image.png

6.XML方式注入其他类型属性

(1)字面量

  1. null值

    <property name="address">
    <null></null>
    </property>
    
  2. 属性值包含特殊符号

image.png
(2)外部bean
xml 注入对象

  1. 创建service,Dao类
  2. 在service调用Dao里的方法
  3. 在spring配置文件中进行配置 ```java public class UserService {

// 创建UserDao类属性,生成set方法

private UserDao userDao;

public UserDao getUserDao() {
    return userDao;
}

public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
}

public void add(){
    System.out.println("service add");

// 原始调用方式 // UserDao userDao = new UserDaoImpl(); // userDao.update();

    // spring方式
    userDao.update();

}

}

```java
public class UserDaoImpl implements UserDao{


    @Override
    public void update() {
        System.out.println("dao update");
    }
}
    <bean id="userService" class="com.atguigu.spring5.service.UserService">
        <property name="userDao" ref="userDaoImpl"></property>
    </bean>

    <bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>

xml 注入集合属性

  1. 注入数组
  2. 注入List集合
  3. 注入Map集合 ```java public class Stu { private String[] courses; private List list; private Map maps; private Set set;

    public void setSet(Set set) { this.set = set; }

    public String[] getCourses() { return courses; }

    public void setCourses(String[] courses) { this.courses = courses; }

    public void setList(List list) { this.list = list; }

    public void setMaps(Map maps) { this.maps = maps; }

    public void test(){ System.out.println(Arrays.toString(courses)); System.out.println(list); System.out.println(maps); System.out.println(set); } }

```java
    <bean id="student" class="com.atguigu.spring5.collectiontype.Stu">
        <!--    数组    -->
        <property name="courses">
            <array>
                <value>Java</value>
                <value>C++</value>
                <value>C#</value>
            </array>
        </property>
        <!--    List    -->
        <property name="list">
            <list>
                <value>Jack</value>
                <value>Rose</value>
            </list>
        </property>
        <!--    Maps    -->
        <property name="maps">
            <map>
                <entry key="Jack" value="Java"></entry>
                <entry key="Rose" value="C++"></entry>
            </map>
        </property>
        <!--    Set    -->
        <property name="set">
            <set>
                <value>MySQL</value>
                <value>Oracle</value>
            </set>
        </property>
    </bean>
  1. 在集合中设置对象

      <property name="coursesList">
          <list>
              <ref bean="course1"></ref>
              <ref bean="course2"></ref>
          </list>
      </property>
    
  2. 集合注入提取成公共部分

(1)在配置文件中引入名称空间util
image.png
(2)

    <util:list id="bookList">
        <value>《哈皮父子》</value>
        <value>《大耳朵图图》</value>
        <value>《猫和老鼠》</value>
    </util:list>

    <bean id="book" class="com.atguigu.spring5.collectiontype.Book">
        <property name="list" ref="bookList"></property>
    </bean>

(3)内部bean和级联赋值

7.IOC操作Bean管理(FactoryBean)

  1. Spring有两种类型bean,一种普通bean,一种工厂bean(FactoryBean)

普通bean:配置文件中定义的类型即为返回类型
工厂bean:在配置文件中定义的类型可以与返回类型不一致
(1)创建一个类,作为工厂bean,实现FactoryBean接口
(2)实现接口方法,定义返回的bean类型

public class MyBean implements FactoryBean {

    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("C");
        return course;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
    @Test
    public void test3() {
        ApplicationContext context  =new ClassPathXmlApplicationContext("bean3.xml");
        Course course = context.getBean("myBean", Course.class);
        System.out.println(course);
    }
    <bean id="myBean" class="com.atguigu.spring5.factorybean.MyBean">
    </bean>

8.bean的作用域

  1. Spring中可以设置创建bean是单实例还是多实例,默认单实例对象

测试:
image.png
结果:
image.png

  1. 设置Spring多实例对象

在Spring配置文件bean标签中有属性scope用于设置
scope:默认singleton单例
prototype多实例
image.png
image.png
request:
session:

  1. singleton与prototype区别

第一:singleton单实例,prototype多实例
第二:设置singleton,当加载spring配置文件时就会创建单实例对象。
设置prototype,是在调用getBean方法时创建多实例对象

9.bean的生命周期

(1)从对象创建到对象销毁的过程
(2)生命周期

  1. 通过构造器创建bean实例
  2. 为bean的属性设置值和对其他bean引用(调用set方法)
  3. 调用bean初始化的方法(需要进行配置)
  4. bean可以使用了
  5. 当容器关闭,调用bean的销毁的方法

    10.xml自动装配

    (1)什么是自动装配

  6. 根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入

(2)示例
标签autowire:byName:根据名称注入,bean中id需要与类中属性名称一致
byType:根据类型注入
image.png

11.引入外部属性文件

(1)直接配置数据库连接信息

  1. 配置德鲁伊连接池
  2. 引入druid连接池依赖

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
      <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
      <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
      <property name="username" value="root"></property>
      <property name="password" value="123456"></property>
    </bean>
    

    (2)通过引入外部文件配置数据库连接池

  3. 创建外部属性文件,存放数据库连接池信息image.png

  4. 外部properties配置文件引入到Spring配置文件中

引入context名称空间
image.png
在配置文件中使用标签引入配置文件

        <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${prop.driverClass}"></property>
            <property name="url" value="${prop.url}"></property>
            <property name="username" value="${prop.userName}"></property>
            <property name="password" value="${prop.password}"></property>
        </bean>

12.基于注解方式

(1)什么是注解
特殊标记:@注解名称(属性=值,属性=值…)
使用注解:类,方法,属性
目的:简化xml配置
(2)Spring针对Bean管理创建对象提供的注解:4个

  • @Component:普通组件
  • @Service:一般用于业务逻辑
  • @Controller:一般用于控制层
  • @Repository:一般用于持久化

四个注解功能是一致的,都可以用来创建bean实例
(3)代码实现

  1. 引入aop依赖
  2. 开启组件扫描

    <!--    开启组件扫描
    扫描多个组件:
    1.多个包使用逗号隔开
    2.扫描包的上层目录
    -->
    <context:component-scan base-package="com.atguigu.spring5"></context:component-scan>
    
  3. 创建类,添加注解

    @Service(value = "userService")
    public class UserService {
    public void add(){
      System.out.println("User service add...");
    }
    }
    

    (4).开启组件扫描细节注意:

  • 可以配置哪些扫描,哪些不扫描
    <context:component-scan base-package="com.atguigu.spring5" use-default-filters="false">
       <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>
    
    (5)属性注入
    (1)@Autowired
    根据属性类型进行自动装配
    1.service与dao类上都添加创建对象注解
    2.在Service中注入dao对象:在service类添加dao类型属性,添加注解
    (2)@Qualifier
    根据名称进行注入
    @Qualifier注解要与@Autowired一起使用
    (3)@Resource
    可根据类型也可根据名称进行注入
    @Resource(name = "userDao")
    private UserDao userDao;
    (4)@Value
    注入普通类型属性
    @Value(value = "ABC")
    private String userName;
    
    (6)纯注解开发
  1. 创建配置类,代替配置文件 ```java @Configuration @ComponentScan(basePackages = {“com.atguigu.spring5”}) public class SpringConfig {

}


   2. 使用(获取bean)

`ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);`
```java
    @Test
    public void testUserService2() {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService =  context.getBean("userService",UserService.class);
        userService.add();
    }

一般基于SpringBoot实现

三、AOP

1.什么是AOP

面向切面编程。对业务逻辑各个部分进行隔离,降低耦合度,提升可重用性
在不修改原有源代码的方式,在主干功能中添加新功能。

2.AOP底层原理

  1. 动态代理

(1)两种情况:
有接口:JDK动态代理
创建UserDao接口实现类代理对象,增强类的方法。
无接口:CGLIB动态代理
创建当前子类的代理对象,增强类的方法。

3.AOP(JDK动态代理)

  1. 使用Proxy类里面的方法创建代理对象

image.png

  1. 三个参数:

类加载器
增强方法所在类实现的接口
实现接口InvocationHandler,创建代理对象,写增强方法

  1. 代码实现:

    1. 创建接口类,定义方法
    2. 创建实现类,实现方法
    3. 使用Proxy类创建接口代理对象 ```java /**
    • @author Created by MrNnobody
    • @date 2021/9/8 9:55
    • Welcome to browse and correct */ public class JdkProxy {

      public static void main(String[] args) { Class[] interfaces = {UserDao.class}; // 使用匿名内部类方式 // Proxy.newProxyInstance(UserDao.class.getClassLoader(), interfaces, new InvocationHandler() { // @Override // public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // return null; // } // }); // 使用实现InvocationHandler方式创建 UserDaoImpl userDao = new UserDaoImpl(); UserDao dao = (UserDao) Proxy.newProxyInstance(UserDao.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = dao.add(1,2); System.out.println(“result” + result); }

}

class UserDaoProxy implements InvocationHandler{

// 1.代理的是谁的对象,就该该对象传过来
//有参构造传递
private Object obj;
public UserDaoProxy(Object obj){
    this.obj = obj;
}

//增强方法

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //执行前
    System.out.println("前" + method.getName() + "传递的参数" + Arrays.toString(args));
    //执行
    Object res = method.invoke(obj,args);
    //执行后
    System.out.println("后" + obj);
    return res;
}

}


4. AOP(术语)
   1. 连接点

类中可以被增强的方法,称为连接点。

   2. 切入点

类中被真正增强的方法。

   3. 通知(增强)

实际增强的逻辑部分<br />通知有多种类型:<br />前置<br />后置<br />环绕<br />异常<br />最终        finally

   4. 切面(过程)

把通知应用到切入点,就叫做切面

5. AOP(准备)

(1)AspectJ<br />独立框架<br />(2)基于AspectJ实现AOP

   1. 基于xml配置

   2. 基于注解

(3)在项目中引入AOP相关依赖<br />(4)切入点表达式<br />语法:<br />execution([权限修饰符] [返回类型] [类全路径] [方法名] ([参数列表]))<br />举例:<br />1.对com.atschool.dao.BookDao 内的add进行增强<br />execution(* com.atschool.dao.BookDao.add(..))<br />2.对com.atschool.dao.BookDao 内的所有方法进行增强<br />execution(* com.atschool.dao.BookDao.*(..))

6. 基于注解AspectJ

(1)创建类,实现方法,对其增强
```java
public class User {
    public void add(){
        System.out.println("add");
    }
}

(2)创建增强类,编写增强逻辑
在增强类中创建方法,不同方法代表不同增强类型
(3)进通知配置

  1. 配置文件中开启注解扫描

image.png

  1. 用注解创建User和UserProxy对象

@Component
public class User {

  1. 在增强类上添加@Aspect注解

@Component
@Aspect
public class UserProxy {

  1. 在spring配置中开启或生成代理对象


  1. 配置不同类型的通知

在增强类里,在作为通知的方法上添加通知类型注解,使用切入点表达式配置

@Component
@Aspect
public class UserProxy {
    @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void before(){
        System.out.println("before");
    }
}