Spring框架

  • Spring是轻量级的开源的JavaEE框架

  • 可以解决企业应用开发的复杂性

  • 两个核心部分:IOC和Aop

    • IOC:控制反转,把创建对象过程交给Spring进行管理
    • Aop:面向切面,不修改源代码进行功能增强

下载

  • 在idea中创建一个maven项目,去 https://mvnrepository.com/ 搜索Spring core的依赖并复制到pom.xml中可自动下载

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.xlh</groupId>
    <artifactId>springdemo01</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.3.9</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.9</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
    <dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.7.0</version>
    <scope>test</scope>
    </dependency>

    </dependencies>
    </project>

第一个例子

  • 通过上述方式可创建一个项目,并使用spring方法创建类

  • 创建一个src/main/java/cn/xlh/add.java

    1
    2
    3
    4
    5
    6
    7
    package cn.xlh;

    public class add {
    public void add_test(){
    System.out.println("测试中:add_test()");
    }
    }
  • src/main/resources下创建一个bean1.xml文件,写入配置信息

    1
    2
    3
    4
    5
    6
    7
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置add对象创建-->
    <bean id="add" class="cn.xlh.add"></bean>
    </beans>
  • 创建一个src/test/java/cn/xlh/testadd.java用于测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package cn.xlh;

    import org.junit.jupiter.api.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class testadd {
    @Test
    public void testAdd(){
    // 加载配置文件
    ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
    add add01 = context.getBean("add", add.class);
    add01.add_test();
    }
    }
  • 运行即可

  • 整体结构

01.jpg

IOC容器

什么是IOC

  • 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
  • 使用IOC目的:为了耦合度降低
  • 第一个例子就是IOC案例

IOC底层原理

  • xml解析、工厂模式、反射
01.jpg

接口

  • IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
  • Spring提供IOC容器实现两种方式:(两个接口)
    • BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
      • 加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
    • ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
      • 加载配置文件时候就会把在配置文件对象进行创建
    • ApplicationContext接口有实现类

Bean管理

  1. 基于xml方式创建对象
    (1)在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
    (2)在bean标签有很多属性,介绍常用的属性
1
2
id属性:唯一标识
class属性:类全路径(包类路径)

(3)创建对象时候,默认也是执行无参数构造方法完成对象创建

1
2
<!--配置add对象创建-->
<bean id="add" class="cn.xlh.add"></bean>
  1. 注入属性

    • 第一种注入方式:使用set方法进行注入

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      // java源文件
      package cn.xlh;

      public class book {
      private String book_name;
      private String book_author;

      public void setBook_name(String book_name) {
      this.book_name = book_name;
      }

      public void setBook_author(String book_author) {
      this.book_author = book_author;
      }
      public String testDemo(){
      return this.book_author+" "+this.book_name;
      }
      }
      1
      2
      3
      4
      5
      6
      <!-- xml文件 -->
      <bean id="book" class="cn.xlh.book">
      <!--属性注入,name为属性名,value为属性值-->
      <property name="book_author" value="肖林航"></property>
      <property name="book_name" value="java"></property>
      </bean>
    • 第二种方式:使用有参构造函数注入

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      package cn.xlh;

      public class book {
      private String book_name;
      private String book_author;

      public book(String book_name, String book_author) {
      this.book_name = book_name;
      this.book_author = book_author;
      }
      public String testDemo() {
      return this.book_author + " " + this.book_name;
      }
      }
      1
      2
      3
      4
      5
      <bean id="book" class="cn.xlh.book">
      <!--构造函数参数-->
      <constructor-arg name="book_name" value="java"></constructor-arg>
      <constructor-arg name="book_author" value="肖林航"></constructor-arg>
      </bean>
  2. xml注入其他类型

    • null

      1
      2
      3
      <property name="book_name">
      <null></null>
      </property>
    • 包含特殊符号

      1
      2
      3
      4
      <!--属性值包含特殊符号 1 把<>进行转义 &lt; &gt; 2 把带特殊符号内容写到CDATA -->
      <property name="address">
      <value><![CDATA[<<南京>>]]></value>
      </property>
    • 注入属性-外部bean

      • 创建两个类 service类和dao类
      • 在service调用dao里面的方法
      • 在spring配置文件中进行配置
      1
      2
      3
      4
      5
      package dao;

      public interface User {
      public void update();
      }
      1
      2
      3
      4
      5
      6
      7
      package dao;

      public class UserImpl implements User {
      public void update() {
      System.out.println("dao update....");
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      package service;

      import dao.User;

      public class Userservice {
      private User user;

      public void setUser(User user) {
      this.user = user;
      }

      public void load() {
      System.out.println("service loading.....");
      // 调用dao方法
      user.update();

      // 传统方法
      // User dao=new UserImpl();
      // dao.update();
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      <bean id="Userservice" class="service.Userservice">
      <!--注入userdao对象
      name:属性名称
      ref:创建userdao对象的标签id
      -->
      <property name="user" ref="dao"></property>
      </bean>
      <bean id="dao" class="dao.UserImpl"></bean>
    • 注入属性-内部bean

      • 在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      //部门类
      public class Dept {
      private String dname;

      public void setDname(String dname) {
      this.dname = dname;
      }
      }

      //员工类
      public class Emp {
      private String ename;
      private String gender;
      // 员工属于某一个部门,使用对象形式表示
      private Dept dept;

      public void setDept(Dept dept) {
      this.dept = dept;
      }

      public void setEname(String ename) {
      this.ename = ename;
      }

      public void setGender(String gender) {
      this.gender = gender;
      }
      }
      • 在spring配置文件中进行配置
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      <!--内部bean-->
      <bean id="emp" class="com.atguigu.spring5.bean.Emp"> <!--设置两个普通属性-->
      <property name="ename" value="lucy"></property>
      <property name="gender" value="女"></property> <!--设置对象类型属性-->
      <property name="dept">
      <bean id="dept" class="com.atguigu.spring5.bean.Dept">
      <property name="dname" value="安保部"></property>
      </bean>
      </property>
      </bean>
    • 注入属性-级联赋值

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      <!-- 第一种级联赋值--> 
      <bean id="emp" class="com.atguigu.spring5.bean.Emp">
      <!--设置两个普通属性-->
      <property name="ename" value="lucy"></property>
      <property name="gender" value="女"></property> <!--级联赋值-->
      <property name="dept" ref="dept"></property>
      </bean>
      <bean id="dept" class="com.atguigu.spring5.bean.Dept">
      <property name="dname" value="财务部"></property>
      </bean>
    • 注入集合类型属性

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      package students;

      import java.util.List;
      import java.util.Map;
      import java.util.Set;

      public class Student {
      //数组
      private String[] arrays;
      //List
      private List<String> list;
      //map
      private Map<String, String> map;
      //set
      private Set<String> set;

      public String[] getArrays() {
      return arrays;
      }

      public List<String> getList() {
      return list;
      }

      public Map<String, String> getMap() {
      return map;
      }

      public Set<String> getSet() {
      return set;
      }

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

      public void setArrays(String[] arrays) {
      this.arrays = arrays;
      }

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

      public void setMap(Map<String, String> map) {
      this.map = map;
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      <bean id="stu" class="students.Student">
      <!--注入数组类型-->
      <property name="arrays">
      <array>
      <value>java</value>
      <value>php</value>
      </array>
      </property>
      <!--注入List类型-->
      <property name="list">
      <list>
      <value>JAVA</value>
      <value>PHP</value>
      </list>
      </property>
      <!--注入Map类型-->
      <property name="map">
      <map>
      <entry key="java" value="JAVA"></entry>
      <entry key="php" value="PHP"></entry>
      </map>
      </property>
      <!--注入Set类型-->
      <property name="set">
      <set>
      <value>HTML</value>
      <value>CSS</value>
      </set>
      </property>
      </bean>
    • 注入集合类型属性(集合存储对象)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      <!--创建多个course对象--> 
      <bean id="course1" class="com.atguigu.spring5.collectiontype.Course">
      <property name="cname" value="Spring5框架"></property>
      </bean>
      <bean id="course2" class="com.atguigu.spring5.collectiontype.Course">
      <property name="cname" value="MyBatis框架"></property>
      </bean>
      <!--注入list集合类型,值是对象-->
      <property name="courseList">
      <list>
      <ref bean="course1"></ref>
      <ref bean="course2"></ref>
      </list>
      </property>
    • 把集合注入部分提取出来

      1
      2
      3
      4
      <!--在spring配置文件中引入名称空间 util -->
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      <!-- 使用util标签完成list集合注入提取 -->
      <!--1 提取list集合类型属性注入-->
      <util:list id="bookList">
      <value>易筋经</value>
      <value>九阴真经</value>
      <value>九阳神功</value>
      </util:list>
      <!--2 提取list集合类型属性注入使用-->
      <bean id="book" class="com.atguigu.spring5.collectiontype.Book">
      <property name="list" ref="bookList"></property>
      </bean>

IOC操作 Bean 管理

FactoryBean

  • Spring有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean)

  • 普通bean:在配置文件中定义bean类型就是返回类型

  • 工厂bean:在配置文件定义bean类型可以和返回类型不一样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // 创建类,让这个类作为工厂bean,实现接口 FactoryBean
    // 实现接口里面的方法,在实现的方法中定义返回的bean类型
    package factory;

    import cn.xlh.book;
    import org.springframework.beans.factory.FactoryBean;


    public class facbean implements FactoryBean<book> {
    //定义返回bean的类型
    public book getObject() throws Exception {
    String s1 = "111", s2 = "222";
    book book = new book(s1, s2);
    return book;
    }

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

    public boolean isSingleton() {
    return false;
    }
    }
    1
    <bean id="fac" class="factory.facbean"></bean>

bean 作用域

  • 在Spring里面,设置创建bean实例是单实例还是多实例

  • 在Spring里面,默认情况下,bean是单实例对象

    1
    2
    3
    book book01 = context.getBean("book", book.class);
    book book02 = context.getBean("book", book.class);
    // 默认两次产生的是同一个
  • bean标签的scope属性可以设置单实例或多实例,singleton为单实例(默认),prototype为多实例

    1
    2
    3
    4
    5
    <bean id="book" class="cn.xlh.book" scope="prototype">
    <!--属性注入,name为属性名,value为属性值-->
    <property name="book_author" value="肖林航"></property>
    <property name="book_name" value="java"></property>
    </bean>
  • 区别

    • singleton单实例,prototype多实例
    • 设置scope值是singleton时候,加载spring配置文件时候就会创建单实例对象
    • 设置scope值是prototype时候,不是在加载spring配置文件时候创建 对象,在调用getBean方法时候创建多实例对象

bean 生命周期

  • 从对象创建到对象销毁的过程
  • 生命周期
    • 通过构造器创建bean实例(无参数构造)
    • 为bean的属性设置值和对其他bean引用(调用set方法)
    • 调用bean的初始化的方法(需要进行配置初始化的方法)
    • bean可以使用了(对象获取到了)
    • 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
  • bean的后置处理器,bean生命周期有七步
    • 通过构造器创建bean实例(无参数构造)
    • 为bean的属性设置值和对其他bean引用(调用set方法)
    • 把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
    • 调用bean的初始化的方法(需要进行配置初始化的方法)
    • 把bean实例传递bean后置处理器的方法 postProcessAfterInitialization
    • bean可以使用了(对象获取到了)
    • 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)

xml 自动装配

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

  • 根据属性名称自动注入

    1
    2
    3
    4
    <!--实现自动装配 bean标签属性autowire,配置自动装配 autowire属性常用两个值: byName根据属性名称注入 ,注入值bean的id值和类属性名称一样 byType根据属性类型注入 --> 
    <bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName">
    </bean>
    <bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
  • 根据属性类型自动注入

    1
    2
    3
    <!--实现自动装配 bean标签属性autowire,配置自动装配 autowire属性常用两个值: byName根据属性名称注入 ,注入值bean的id值和类属性名称一样 byType根据属性类型注入 --> 
    <bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byType">
    </bean> <bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>

外部属性文件

* 创建外部属性文件,properties格式文件,写数据库信息
* 把外部properties属性文件引入到spring配置文件中引入context名称空间
* 在spring配置文件使用标签引入外部属性文件

基于注解管理(重要)

什么是注解

(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:简化xml配置

Spring针对Bean管理中创建对象提供注解

(1)@Component
(2)@Service
(3)@Controller
(4)@Repository

上面四个注解功能是一样的,都可以用来创建bean实例

基于注解方式实现对象创建

  • 引入spring-aop依赖

  • bean1.xml中开启组件扫描

    1
    <context:component-scan base-package="cn.xlh"></context:component-scan>
  • 创建类,在类上面添加创建对象注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package cn.xlh;

    import org.springframework.stereotype.Component;

    @Component(value = "book1") // 相当于<bean id="book1" class="..."><bean>
    //value可省略,默认为类名(首字母小写)
    public class book {
    private String book_name;
    private String book_author;
    }
  • 测试

    1
    2
    3
    4
    5
    6
    7
    @Test
    public void test05() {
    // 加载配置文件
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    book book1 = context.getBean("book1", book.class);
    System.out.println(book1);
    }

细节管理

1
2
3
4
5
6
7
8
9
 <!--示例1 use-default-filters="false" 表示现在不使用默认filter,自己配置filter context:include-filter ,设置扫描哪些内容 --> 
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<!--这里表示只扫描带有controller注解的-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--示例2 下面配置扫描包所有内容 context:exclude-filter: 设置哪些内容不进行扫描 -->
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

属性注入

  • @Autowired:根据属性类型进行自动装配

    • 把service和dao对象创建,在service和dao类添加创建对象注解
    • 在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解
    1
    2
    3
    4
    5
    6
    7
    8
    package dao;

    import org.springframework.stereotype.Repository;

    @Repository
    public interface UserDao {
    public void add();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package dao;

    import org.springframework.stereotype.Repository;

    @Repository
    public class UserDaoImpl implements UserDao{
    public void add() {
    System.out.println("UserDaoImpl add....!");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    javapackage service;

    import dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    @Service
    public class Service2 {
    //不需要set方法,添加注解实现
    @Autowired
    private UserDao userDao;

    public void addTest() {
    System.out.println("service loading.....");
    // 调用dao方法
    userDao.add();
    }
    }
    • 测试即可
  • @Qualifier:根据名称进行注入。@Qualifier注解的使用,和上面@Autowired一起使用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package service;

    import dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Service;

    @Service
    public class Service2 {
    //不需要set方法,添加注解实现
    @Autowired
    //给实现类注解加名字后,按照名字创建该类
    @Qualifier(value = "userDao01")
    private UserDao userDao;

    public void addTest() {
    System.out.println("service loading.....");
    // 调用dao方法
    userDao.add();
    }
    }
  • @Resource:可以根据类型注入,可以根据名称注入

    1
    2
    3
    //@Resource     // 按照属性类型
    @Resource(name = "userDao01") // 按照属性名
    private UserDao userDao;
  • @Value:注入普通类型属性

    1
    2
    @Value(value = "xlh")       // 将xlh注入name中
    private String name;

完全注解开发

  • 创建配置类,替代xml配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package config;

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

    @Configuration // 作为配置类,代替xml
    @ComponentScan(basePackages = {"service","cn.xlh","dao"})
    public class SpringConfig {

    }
  • 编写测试类

    1
    2
    3
    4
    5
    6
    7
    @Test
    public void test06() {
    // 加载配置文件
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    Service2 service2 = context.getBean("service2", Service2.class);
    service2.addTest();
    }

AOP

  • 面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
  • 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能。

动态代理

  • 有接口情况,使用JDK动态代理

    • 创建接口实现类代理对象,增强类的方法

    01.jpg

  • 没有接口情况,使用CGLIB动态代理

    • 创建子类的代理对象,增强类的方法

    01.jpg

JDK动态代理

  • 使用JDK动态代理,使用Proxy类里面的方法创建代理对象

  • 调用newProxyInstance方法

    1
    2
    static Object	newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)
    返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
    • 方法有三个参数:
      • 第一参数,类加载器
      • 第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
      • 第三参数,实现这个接口InvocationHandler,创建代理对象,写增强的部分
  • 编写JDK动态代理代码

    • 创建接口,定义方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package dao;

    public class CarDaoImpl implements CarDao {
    @Override
    public int add(int a, int b) {
    return 0;
    }

    @Override
    public String update(String id) {
    return null;
    }
    }
    • 创建接口实现类,实现方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package dao;

    public class CarDaoImpl implements CarDao {
    @Override
    public int add(int a, int b) {
    return 0;
    }

    @Override
    public String update(String id) {
    return null;
    }
    }
    • 使用Proxy类创建接口代理对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    package dao;

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

    public class JDKProxy {
    public static void main(String[] args) {
    //创建接口实现类代理对象
    Class[] interfaces={CarDao.class};
    //Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
    // //匿名方式
    // public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // return null;
    // }
    //});
    CarDaoImpl carDao=new CarDaoImpl();
    CarDao carDao1= (CarDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new CarDaoProxy(carDao));
    int res=carDao1.add(10,20);
    System.out.println(res);
    }
    }
    //创建代理对象
    class CarDaoProxy implements InvocationHandler{
    //创建的是谁的对象就把谁传过来
    private Object obj;
    public CarDaoProxy(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;

    }
    }

AOP操作术语

  • 连接点
    • 类里哪些方法可以被增强,这些方法就被认为是连接点
  • 切入点
    • 实际被增强的方法,称为切入点
  • 通知(增强)
    • 实际增强的逻辑部分称为通知
    • 类型
      • 前置通知‘
      • 后置通知
      • 环绕通知
      • 异常通知
      • 最终通知
  • 切面
    • 把通知应用到切入点

AOP准备

  • Spring框架一般都是基于AspectJ实现AOP操作

    • AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spirng框架一起使用,进行AOP操作
  • 基于AspectJ实现AOP操作

    • 基于xml配置文件实现
    • 基于注解方式实现(使用)
  • 在项目工程里面引入AOP相关依赖

  • 切入点表达式

    • 切入点表达式作用:知道对哪个类里面的哪个方法进行增强
    • 语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) )
  • 举例

    1
    2
    3
    4
    5
    6
    举例1:对com.atguigu.dao.BookDao类里面的add进行增强
    execution(* com.atguigu.dao.BookDao.add(..))
    举例2:对com.atguigu.dao.BookDao类里面的所有的方法进行增强
    execution(* com.atguigu.dao.BookDao.* (..))
    举例3:对com.atguigu.dao包里面所有类,类里面所有方法进行增强
    execution(* com.atguigu.dao.*.* (..))

AOP操作(基于AspectJ注解)

  • 创建类,在类里面定义方法

    1
    2
    3
    4
    5
    6
    7
    8
    package aop;


    public class User {
    public void add(){
    System.out.println("aop.User add.....");
    }
    }
  • 创建增强类(编写增强逻辑)

    • 在增强类里面,创建方法,让不同方法代表不同通知类型
    1
    2
    3
    4
    5
    6
    7
    8
    9
    package aop;

    //增强类
    public class UserProxy {
    //前置通知
    public void before(){
    System.out.println("before.....");
    }
    }
  • 进行通知的配置

    • 在spring配置文件中,开启注解扫描

      1
      <context:component-scan base-package="aop"></context:component-scan>
    • 使用注解创建User和UserProxy对象

      1
      2
      3
      4
      5
      6
      @Component
      public class User {

      //增强类
      @Component
      public class UserProxy {
    • 在增强类上面添加注解 @Aspect

      1
      2
      3
      4
      //增强类
      @Component
      @Aspect //生成代理对象
      public class UserProxy {
    • 在spring配置文件中开启生成代理对象

      1
      2
      <!--开启Aspect生成代理对象-->
      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    • 配置不同类型的通知

      • 在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      package aop;

      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.*;
      import org.springframework.stereotype.Component;

      //增强类
      @Component
      @Aspect //生成代理对象
      public class UserProxy {
      //前置通知
      //Before 注解表示前置通知
      @Before(value = "execution(* aop.User.add(..))")
      public void before() {
      System.out.println("before.....");
      }

      //后置通知(返回通知)
      @AfterReturning(value = "execution(* aop.User.add(..))")
      public void afterReturning() {
      System.out.println("afterReturning.....");
      }

      //最终通知
      @After(value = "execution(* aop.User.add(..))")
      public void after() {
      System.out.println("after.....");
      }

      //异常通知
      @AfterThrowing(value = "execution(* aop.User.add(..))")
      public void afterThrowing() {
      System.out.println("afterThrowing.....");
      }

      //环绕通知
      @Around(value = "execution(* aop.User.add(..))")
      public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
      System.out.println("环绕前...");
      // 被增强的方法执行
      proceedingJoinPoint.proceed();
      System.out.println("环绕后...");
      }
      }
  • 测试及结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    @Test
    public void test07() {
    // 加载配置文件
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    User user = context.getBean("user", User.class);
    user.add();
    }

    // 输出结果
    环绕前...
    before.....
    aop.User add.....
    afterReturning.....
    after.....
    环绕后...

    Process finished with exit code 0
  • 相同切入点抽取

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //相同切入点抽取
    @Pointcut(value = "execution(* aop.User.add())")
    public void pointcut() {

    }

    //前置通知
    //Before 注解表示前置通知
    @Before(value = "pointcut()")
    public void before() {
    System.out.println("before.....");
    }
  • 有多个增强类多同一个方法进行增强,设置增强类优先级

    1
    2
    3
    4
    5
    //增强类
    @Component
    @Aspect //生成代理对象
    @Order(1)
    public class UserProxy {
  • 完全使用注解开发

    • 创建配置类,不需要创建xml配置文件

      1
      2
      3
      4
      5
      6
      @Configuration 
      @ComponentScan(basePackages = {"com.atguigu"})
      @EnableAspectJAutoProxy(proxyTargetClass = true)
      public class ConfigAop {

      }

AOP操作(AspectJ配置文件)

  • 创建两个类,增强类和被增强类,创建方法

  • 在spring配置文件中创建两个类对象

    1
    2
    3
    <!--创建对象-->
    <bean id="book" class="aop.Book"></bean>
    <bean id="bookProxy" class="aop.BookProxy"></bean>
  • 在spring配置文件中配置切入点

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!--配置aop增强-->
    <aop:config>
    <!--切入点-->
    <aop:pointcut id="p" expression="execution(* aop.Book.buy())"></aop:pointcut>
    <!--配置切面-->
    <aop:aspect ref="bookProxy">
    <!--增强作用在具体的方法上-->
    <aop:before method="before" pointcut-ref="p"></aop:before>
    </aop:aspect>
    </aop:config>

JdbcTemplate

什么是JdbcTemplate

Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作。

准备工作

  • 引入相关jar包

  • 在spring配置文件配置数据库连接池

    1
    2
    3
    4
    5
    6
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>
  • 配置JdbcTemplate对象,注入DataSource

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启组件扫描-->
    <context:component-scan base-package="JdbcTemplate"></context:component-scan>

    <!--数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>

    <!--jdbcTemplate对象-->
    <bean id="dbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--注入dataSource-->
    <property name="dataSource" ref="dataSource"></property>
    </bean>
    </beans>
  • 创建service类,创建dao类,在dao注入jdbcTemplate对象

    1
    2
    3
    4
    package JdbcTemplate.dao;

    public interface BookDao {
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    package JdbcTemplate.dao;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;

    @Repository
    public class BookDaoImpl implements BookDao{
    //注入jdbctemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package JdbcTemplate.service;

    import JdbcTemplate.dao.BookDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    @Service
    public class BookService {
    //注入BookDao
    @Autowired
    private BookDao bookDao;

    }

JdbcTemplate操作数据库(添加)

  • 在dao进行数据库添加操作
  • 调用JdbcTemplate对象里面update方法实现添加操作
    • 有两个参数
    • 第一个参数:sql语句
    • 第二个参数:可变参数,设置sql语句值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package JdbcTemplate.entity;

public class Book {
private String id;
private String name;
private String status;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}
}
1
2
3
4
5
6
7
package JdbcTemplate.dao;

import JdbcTemplate.entity.Book;

public interface BookDao {
public void add(Book book);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package JdbcTemplate.dao;

import JdbcTemplate.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class BookDaoImpl implements BookDao{
//注入jdbctemplate
@Autowired
private JdbcTemplate jdbcTemplate;

@Override
public void add(Book book) {
//创建sql语句
String sql="insert into t_book values(?,?,?)";
//调用方法实现
Object[] args={book.getId(),book.getName(),book.getStatus()};
int update=jdbcTemplate.update(sql,args);
System.out.println(update);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package JdbcTemplate.dao;

import JdbcTemplate.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class BookDaoImpl implements BookDao{
//注入jdbctemplate
@Autowired
private JdbcTemplate jdbcTemplate;

@Override
public void add(Book book) {
//创建sql语句
String sql="insert into t_book values(?,?,?)";
//调用方法实现
Object[] args={book.getId(),book.getName(),book.getStatus()};
int update=jdbcTemplate.update(sql,args);
System.out.println(update);
}
}
1
2
3
4
5
6
7
8
9
10
11
@Test
public void test08() {
// 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book();
book.setId("111");
book.setName("肖林航");
book.setStatus("333");
bookService.add(book);
}

JdbcTemplate操作数据库(修改和删除)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public void update(Book book) {
//创建sql语句
String sql = "UPDATE t_book SET name=?,status=? WHERE id=?";
//调用方法实现
Object[] args = {book.getName(), book.getStatus(), book.getId()};
int update = jdbcTemplate.update(sql, args);
System.out.println(update);
}

@Override
public void delete(String id) {
//创建sql语句
String sql = "DELETE FROM t_book WHERE id=?";
//调用方法实现
int update = jdbcTemplate.update(sql, id);
System.out.println(update);
}

JdbcTemplate操作数据库(查询)

查询返回某个值

  • 查询表里面有多少条记录,返回是某个值
1
2
3
4
5
6
7
8
//查询记录数
@Override
public int selectCount() {
String sql = "select count(*) from t_book";
// queryForObject()第一个参数sql语句,第二个参数:返回类型Class
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
return count;
}

查询返回对象

  • 场景:查询图书详情

01.jpg

  • 有三个参数
    • 第一个参数:sql语句
    • 第二个参数:RowMapper是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装
    • 第三个参数:sql语句值
1
2
3
4
5
6
@Override
public Book findBookInfo(String id) {
String sql="select * from t_book where id=?";
Book book=jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),id);
return book;
}

查询返回集合

  • 场景:查询图书列表分页…

01.jpg

  • 有三个参数
    • 第一个参数:sql语句
    • 第二个参数:RowMapper是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装
    • 第三个参数:sql语句值
1
2
3
4
5
6
@Override
public List<Book> findAllBook() {
String sql = "select * from t_book";
List<Book> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
return list;
}

JdbcTemplate操作数据库(批量操作)

  • JdbcTemplate实现批量添加操作

01.jpg

  • 有两个参数
    • 第一个参数:sql语句
    • 第二个参数:List集合,添加多条记录数据
1
2
3
4
5
6
7
//批量添加 
@Override
public void batchAddBook(List<Object[]> batchArgs) {
String sql = "insert into t_book values(?,?,?)";
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints));
}