Spring

控制反转IOC(Inversion of Control)

  • 使用对象时,有主动new产生对象转为外部提供对象,对象控制权由程序转移到外部,此思想称为控制反转。

IOC就是上面所提到的“外部”,管理大量的对象,负责对象的创建、初始化等一系列工作,被创建或者被管理的对象在IoC容器中称为Bean

依赖注入DI(Dependency InJection)

  • 在容器中建立bean与bean之间的依赖关系的整个过程,称为以来注入。(比如service和dao之间的依赖关系)

目标:充分解耦

使用的时候不单可以直接从IoC容器中获取,而且获取到的bean已经绑定了所有的依赖关系。


IOC快速入门##

service层

BookService

package com.itheima.service;

public interface BookService {
    void save();
}

BookServiceImpl

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.impl.BookDaoImpl;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService {
    BookDao bookDao=new BookDaoImpl();

    public void save(){
        System.out.println("book service save ...");
        bookDao.save();
    }
}

Dao层

BookDao

package com.itheima.dao;

public interface BookDao {
    public void save();
}

BookDaoImpl

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    public void save(){
        System.out.println("book dao save...");
    }
}

主方法App

package com.itheima;

import com.itheima.service.BookService;
import com.itheima.service.impl.BookServiceImpl;


public class App {
    public static void main(String[] args) {
        System.out.println("111");
    }
}

运行之后控制台显示

book service save ...
book dao save...

下面开始用spring的文件

在pom.xml里面添加坐标

<?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>org.example</groupId>
    <artifactId>spring01</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>

    </dependencies>
</project>

新建一个applicationContext.xml

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

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"></bean>
    <bean id="booService" class="com.itheima.service.impl.BookServiceImpl"></bean>
</beans>

主方法里面

package com.itheima;

import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        BookService bookService = (BookService) applicationContext.getBean("bookService");
        bookService.save();
    }
}

会发现,此时控制台也输出了和前面一样的结果。

DI入门(XML版)

  1. 基于上面的IoC管理bean
  2. Service中使用new的形式不能保留
  3. Service中需要的Dao对象如何进入到Service中?提供方法
  4. Service和Dao的关系如何描述?用配置

在BookServiceImpl中删除new形式创建对象,增加一个设置bookDao的方法

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.impl.BookDaoImpl;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService {
//    BookDao bookDao=new BookDaoImpl();删除该方法的new形式
    private BookDao bookDao;

    //创建一个新的方法设置bookDao
    public void setBookDao(BookDao bookDao){
        this.bookDao=bookDao;
    }

    public void save(){
        System.out.println("book service save ...");
        bookDao.save();
    }
}

在applicationContext中配置bean之间的关系

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

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <!--new↓-->
        <property name="bookDao" ref="bookDao"></property>
    </bean>
</beans>

在property标签中

name表示配置哪一个属性,这里是BookServiceImpl中的bookDao属性 (private BookDao bookDao;)

ref表示参照的是哪个bean,值是其他bean的id,这里显示的就是bookDao的bean的id

运行发现,结果能达到一样的效果

bean的配置↓

别名

  1. bean标签可以用name来设置别名,可以用逗号、分号或者空格来隔开设置多个别名
  2. bean和bean之间也可以用别名引用

spring默认给我们创造的bean是单例吗?

public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        BookService bookService1 = (BookService) applicationContext.getBean("bookService");
        BookService bookService2 = (BookService) applicationContext.getBean("bookService");
        System.out.println(bookService1);
        System.out.println(bookService2);
    }
}

运行结果是

com.itheima.service.impl.BookServiceImpl@25bbe1b6
com.itheima.service.impl.BookServiceImpl@25bbe1b6

可以看到获取到的默认是同样的对象,即证明是单例,如果需要创建非单例怎么创建呢?

我们可以去配置类applicationContext.xml中的bean标签里添加scope属性

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

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" scope="prototype">
        <property name="bookDao" ref="bookDao"></property> 
    </bean>
</beans>

再次运行结果,发现已经变成了两个对象

com.itheima.service.impl.BookServiceImpl@25bbe1b6
com.itheima.service.impl.BookServiceImpl@5702b3b1

scope的属性:

  1. "prototype"非单例
  2. "singleton"单例(默认)

这里就体现了spring的优点,默认为单例,提高bean内容的复用性,不用像曾经一样,用一次new一个对象。但是有不适用单例的情况,比如说封装的实体类对象,因为每次数据不一样,所以不能重用。

bean实例化(构造方法.常用)↓

bean本质上就是对象,创建bean是使用无参的构造方法完成的

在BookDaoImpl中添加无参构造方法

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    public void save(){
        System.out.println("book dao save...");
    }
//new↓
    public BookDaoImpl() {
        System.out.println("bookdao Construct!!!");
    }
}

运行后会发现无参构造方法中的语句运行了。就算是设置为private私有的构造方法也能访问,说明其是通过反射实现。

bean实例化(静态工厂实例化bean.了解)↓

创建好 OrderDao和实现类OrderDaoImpl、OrderDaoFactory。

OrderDao

package com.itheima.order;

public interface OrderDao {
    void save();
}

OrderDaoImpl

package com.itheima.order.impl;

import com.itheima.order.OrderDao;

public class OrderDaoImpl implements OrderDao {
    public void save(){
        System.out.println("order dao save");
    }
}

OrderDaoFactory

package com.itheima.factory;

import com.itheima.order.OrderDao;
import com.itheima.order.impl.OrderDaoImpl;

public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        return new OrderDaoImpl();
    }
}

配置类修改

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

    <bean id="orderdao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"></bean>
</beans>

class只是获取到了工厂的对象,而用factory-method才能具体到获取工厂所构建的指定方法

bean实例化(实例工厂实例化bean.了解)↓

Factory中的方法变为非静态

package com.itheima.factory;

import com.itheima.order.OrderDao;
import com.itheima.order.impl.OrderDaoImpl;

public class OrderDaoFactory {
    public OrderDao getOrderDao(){
        return new OrderDaoImpl();
    }
}

之前静态方法中的 public static OrderDao getOrderDao(){} 改为

    public OrderDao getOrderDao(){}

所以在主方法中,需要实例化一个OrderDaoFactory,从OrderDaoFactory再获取orderDao对象

public class App {
    public static void main(String[] args) {
    OrderDaoFactory orderDaoFactory=new OrderDaoFactory();
    OrderDao orderDao=orderDaoFactory.getOrderDao();
    orderDao.save();
    }
}

此时运行结果

order dao save

配置类

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

    <bean id="orderDaoFactory" class="com.itheima.factory.OrderDaoFactory"></bean>
    <bean id="orderDao" factory-bean="orderDaoFactory" factory-method="getOrderDao"></bean>
</beans>

先把工厂的bean造出来,然后创建一个新的bean,factory-bean设置所属工厂,factory-method设置工厂的指定方法

public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        OrderDao orderDao= (OrderDao) applicationContext.getBean("orderDao");
        orderDao.save();
    }
}

运行结果

order dao save

bean实例化(Factorybean.实用掌握)↓

创建一个UserDaoFactoryBean替代原本的OrderDaoFactory

package com.itheima.factory;

import com.itheima.order.OrderDao;
import com.itheima.order.impl.OrderDaoImpl;
import org.springframework.beans.factory.FactoryBean;

public class UserDaoFactoryBean implements FactoryBean<OrderDao> {
    //代替原始实例工厂中创建对象的方法
    public OrderDao getObject() throws Exception {
        return new OrderDaoImpl();
    }

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

applicationContext.xml

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

    <bean id="orderDao" class="com.itheima.factory.UserDaoFactoryBean"></bean>
</beans>

运行结果:

order dao save

此时如果想要设置非单例,需要在实现FactoryBean接口的方法(在这个例子中是UserDaoFactoryBean实现的)中加上Singleton();return为false

bean生命周期(手动配置控制)

在UserDaoFactoryBean加入两个方法init和destory

package com.itheima.factory;

import com.itheima.order.OrderDao;
import com.itheima.order.impl.OrderDaoImpl;
import org.springframework.beans.factory.FactoryBean;

public class UserDaoFactoryBean implements FactoryBean<OrderDao> {
    //代替原始实例工厂中创建对象的方法
    public OrderDao getObject() throws Exception {
        return new OrderDaoImpl();
    }

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


    void init(){
        System.out.println("init");
    }

    void destory(){
        System.out.println("destory");
    }
}

配置类中bean标签中加入init-method和destroy-method属性

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

    <bean id="orderDao" class="com.itheima.factory.UserDaoFactoryBean" init-method="init" destroy-method="destory"></bean>
</beans>

因为配置类中的bean标签的class是指向UserDaoFactoryBean,所以在UserDaoFactoryBean添加init和destory两个方法体

运行结果:

init
order dao save

这时候发现destory方法没有运行,为什么呢?
我们写的程序是运行在java虚拟机中的,程序执行完了之后,虚拟机就强行退出了而没有销毁bean,所以的destory还得不到执行。

在主方法中,将ApplicationContext改成ClassPathXmlApplicationContext
package com.itheima;

import com.itheima.order.OrderDao;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        OrderDao orderDao= (OrderDao) applicationContext.getBean("orderDao");
        orderDao.save();
        applicationContext.close();
    }
}

运行结果:

init
order dao save
destory

ClassPathXmlApplicationContext是ApplicationContext的子类,其中才有close的实现方法,不过这是一种暴力关闭的方法。

方法2:

package com.itheima;

import com.itheima.order.OrderDao;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        applicationContext.registerShutdownHook();
        OrderDao orderDao= (OrderDao) applicationContext.getBean("orderDao");
        orderDao.save();
    }
}

applicationContext.registerShutdownHook()是在虚拟机关闭之前,再把bean给销毁,达到同样的作用。

除了手动配置,还有实现接口控制bean生命周期。

依赖注入↓

思考:向一个类中传递数据的方式有几种?

  1. 普通set方法
  2. 构造方法

依赖注入描述了在容器中建立bean和bean之间依赖关系的过程,如果bean运行需要的是数字或者字符串呢?

  1. 引用类型
  2. 简单类型(基本数据类型与String

依赖注入的方式

  1. setter注入
    简单类型
    引用类型

  2. 构造器注入
    简单类型
    引用类型


setter注入.引用类型↓

OrderDaoImpl

package com.itheima.order.impl;

import com.itheima.order.OrderDao;

public class OrderDaoImpl implements OrderDao {
    public void save(){
        System.out.println("order dao save!!!!!!!!!");
    }
}

BookDaoImpl

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    public void save(){
        System.out.println("book dao save..........");
    }
}

BookServiceImpl

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.order.OrderDao;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService {
    private OrderDao orderDao;
    private BookDao bookDao;

    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save(){
        System.out.println("book service save ...");
        bookDao.save();
        orderDao.save();
    }
}

配置类

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

    <bean id="orderDao" class="com.itheima.order.impl.OrderDaoImpl" />
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"></property>
        <property name="orderDao" ref="orderDao"></property>
    </bean>
</beans>

setter注入.简单类型↓

在上述的代码中,修改BookDaoImpl,添加ab两个变量,并且提供setter方法

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    private int a;
    private String b;

    public void setA(int a) {
        this.a = a;
    }

    public void setB(String b) {
        this.b = b;
    }

    public void save() {
        System.out.println("book dao save.........."+a+b);
    }
}

修改配置文件,使用bean标签的子标签property,用name获取变量名,用value设置值

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

    <bean id="orderDao" class="com.itheima.order.impl.OrderDaoImpl"></bean>
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="a" value="1000"></property>
        <property name="b" value="万恶之源!"></property>
    </bean>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao" ></property>
        <property name="orderDao" ref="orderDao"></property>
    </bean>
</beans>

运行结果:

book service save ...
book dao save..........1000万恶之源!
order dao save!!!!!!!!!

构造器注入.引用类型↓

在上述的基础上修改BookServiceImpl,不难发现其中的setter方法变成了通过构造方法,去引用类对象

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.impl.BookDaoImpl;
import com.itheima.order.OrderDao;
import com.itheima.order.impl.OrderDaoImpl;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    private OrderDao orderDao;

    public BookServiceImpl(BookDaoImpl bookDao1, OrderDaoImpl orderDao1) {
        this.orderDao=orderDao1;
        this.bookDao=bookDao1;
    }

    public void save(){
        System.out.println("book service save ...");
        orderDao.save();
        bookDao.save();
    }
}

修改配置文件,在id为bookService的bean中用constructor-arg标签,通过name引用BookServiceImpl中的形参(bookDao1和orderDao1),ref引用代码上部分的两个bean,让他们形成依赖。

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

    <bean id="orderDao" class="com.itheima.order.impl.OrderDaoImpl"></bean>
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="a" value="1000"></property>
        <property name="b" value="万恶之源!"></property>
    </bean>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao1" ref="bookDao"></constructor-arg>
        <constructor-arg name="orderDao1" ref="orderDao"></constructor-arg>
    </bean>
</beans>

运行结果:

book service save ...
order dao save!!!!!!!!!
book dao save..........1000万恶之源!

构造器注入.简单类型↓

在上述基础上修改BookDaoImpl,将获取变量的setter方法换成有ab两个参数的构造方法

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    private int a;
    private String b;

    public BookDaoImpl(int a, String b) {
        this.a = a;
        this.b = b;
    }


    public void save() {
        System.out.println("book dao save.........."+a+b);
    }
}

修改配置类,将id为bookDao的bean下的property标签换成constructor-arg标签,用name和value结合传参数

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

    <bean id="orderDao" class="com.itheima.order.impl.OrderDaoImpl"></bean>
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <constructor-arg name="a" value="20000"></constructor-arg>
        <constructor-arg name="b" value="十恶不赦"></constructor-arg>
    </bean>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao1" ref="bookDao"></constructor-arg>
        <constructor-arg name="orderDao1" ref="orderDao"></constructor-arg>
    </bean>
</beans>

运行结果:

book service save ...
order dao save!!!!!!!!!
book dao save..........20000十恶不赦

上述的构造器配置中的constructor的name属性必须和类中形参一致,形参要是改名配置也要改名,这样耦合度太高,解决方法

  1. 使用type,让其根据类型去找

     <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
         <constructor-arg type="int" value="20000"></constructor-arg>
         <constructor-arg type="java.lang.String" value="十恶不赦"></constructor-arg>
     </bean>
    
  2. 使用index,根据索引去找,不过要注意顺序

     <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
         <constructor-arg index="0" value="20000"></constructor-arg>
         <constructor-arg index="1" value="十恶不赦"></constructor-arg>
     </bean>
    

依赖自动装配↓

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

  • 自动装配用于引用类型,不能用于简单类型

  • 自动装配优先级低于setter注入和构造器注入,同时出现时自动装配失效

    -src
    --main
    ---java
    ----com
    -----itheima
    ------App.java
    ------dao
    -------BookDao.java
    -------impl
    --------BookDaoImpl.java
    ------service
    -------BookService.java
    -------impl
    --------BookServiceImpl.java
    ---resources
    ----applicationContext.xml
    (接口类省略)

BookDaoImpl

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save..........");
    }
}

BookServiceImpl

package com.itheima.service.impl;


import com.itheima.dao.BookDao;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

applicationContext.xml

<?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">
    
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
</beans>

在实现类中提供setter方法,然后去配置类里面的bean里面加上autowire="byType"属性,这里是根据类型自动装配,要唯一,type名就是bean中的class名。

集合注入↓##

在BookDaoImpl做出以下修改(它的接口类省略)

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

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

public class BookDaoImpl implements BookDao {
    private int[] array;
    private List<String> list;
    private Set<String> set;
    private Map<String, String> map;
    private Properties properties;

    public void setArray(int[] array) {
        this.array = array;
    }

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

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

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }


    public void save() {
        System.out.println("book dao save..........");
        System.out.println("array:"+array);
        System.out.println("list:"+list);
        System.out.println("set:"+set);
        System.out.println("map:"+map);
        System.out.println("properties:"+properties);
    }

}

配置类

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

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>suyang</value>
                <value>xingxing</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>10000</value>
                <value>30000</value>
                <value>50000</value>
                <value>40000</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry value="灭霸" key="1"></entry>
                <entry value="幻视" key="2"></entry>
                <entry value="女巫" key="3"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="1" >mieba</prop>
                <prop key="2" >huanshi</prop>
                <prop key="3" >nvwu</prop>
            </props>
        </property>

    </bean>
</beans>

运行结果:

book dao save..........
array:[I@1f28c152
list:[suyang, xingxing]
set:[10000, 30000, 50000, 40000]
map:{1=灭霸, 2=幻视, 3=女巫}
properties:

数据源对象管理 ↓##

先在pom.xml添加坐标

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.24</version>
    </dependency>
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>

Druid

<?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">·
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value=""></property>
        <property name="url" value=""></property>
        <property name="username" value=""></property>
        <property name="password" value=""></property>
    </bean>
</beans>

c3p0

<bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value=""></property>
    <property name="jdbcUrl" value=""></property>
    <property name="user" value=""></property>
    <property name="password" value=""></property>
</bean>

加载properties文件

上述的加载方式不够灵活,所以需要另外加一个jdbc的信息配置类jdbc.properties

jdbc.driver="com.jdbc.mysql.Driver"
jdbc.url="jdbc:mysql://localhost:3306/day17"
jdbc.username=root
jdbc.password=123456

在配置类中开启context命名空间,启用占位符

<?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
       http://www.springframework.org/schema/context/spring-context.xsd
       ">
    <context:property-placeholder location="jdbc.properties"></context:property-placeholder>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <bean id="getname" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="name" value="${jdbc.username}"></property>
    </bean>

</beans> 

通过id为getname的方法就可以验证是否配置成功

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) applicationContext.getBean("getname");
        bookDao.save();
    }
}     

运行结果:

jdbc.name:root

如果jdbc.properties配置中的jdbc.username=root改为username=root,会发生什么???
把所有jdbc.username替换成username后

运行结果:

jdbc.name:Administrator

这是因为系统环境变量中,系统名的优先级最高,所以username首先是系统的用户名。
如果一定要使username为自己所用怎么办呢?

A:在配置文件的context标签中添加一个system-properties-mode="NEVER"属性

<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"></context:property-placeholder>

加载当前工程下的多个.properties文件添加属性:location="classpath:*.properties"

<context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"></context:property-placeholder>

加载包括引用jar包等所有的.properties文件添加属性:location="classpath:.properties"

<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"></context:property-placeholder>

注解开发↓

如果都是用@Component注解会混乱,所以衍生了
@Controller:用于表现层的bean
@Service:用于业务层的bean
@Repository:用于数据层的bean

使用@Component定义bean

配置类

<?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
       http://www.springframework.org/schema/context/spring-context.xsd
       ">
    <context:component-scan base-package="com.itheima"></context:component-scan>
</beans>

BookDaoImpl

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.stereotype.Component;


@Component("bookDao")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("bookDao....");
    }
}

主方法

package com.itheima;


import com.itheima.dao.BookDao;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) applicationContext.getBean("bookDao");
        bookDao.save();
    }
}

纯注解开发

Spring3.0开启了纯注解开发模式,用java类来代替了配置文件

BookDaoImpl加入@Repository("bookDao")注解

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;


@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("bookDao....");
    }
}

在config包下面创建一个SpringConfig类,@Configuration注明这是配置类,@ComponentScan负责扫描的范围

package com.itheima.config;

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

@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {

}

@Configuration代替了

<?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
       http://www.springframework.org/schema/context/spring-context.xsd
       ">
       
       <context:component-scan base-package="com.itheima"></context:component-scan>
       
</beans>

@ComponentScan("com.itheima")代替其中的

<context:component-scan base-package="com.itheima"></context:component-scan>

主方法通过AnnotationConfigApplicationContext来加载配置类SpringConfig

package com.itheima;


import com.itheima.config.SpringConfig;
import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao= (BookDao) applicationContext.getBean("bookDao");
        bookDao.save();

    }
}

bean的作用范围用@Scope注解
## 注解开发依赖注入 ↓##

BookDaoImpl

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;


@Repository("bookDao")
@Scope("prototype")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("bookDao....");
    }
}

SpringConfig
Fpro
package com.itheima.config;

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

@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {

}

BookServiceImpl,使用@Autowired注解之后就不需要setter方法了,@Autowired注解默认按照类型装配

package com.itheima.service.impl;


import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service

public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

简单类型注入

@Value("${}")
private int a;\

获取${}需要去配置类中加上@PropertySource()数据源注解,注明数据来源,文件名不支持*.xxx的格式。

管理第三方bean ↓##

创建一个新的类,在类中创建一个方法,在该方法上加@Bean,意在让其返回值成为一个Bean。
@import可以在配置类中导入别的配置类

AOP入门案例

pom.xml

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.example</groupId>
    <artifactId>SpringAndMybatis</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>Maven Quick Start Archetype</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.20</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>
    </dependencies>
</project>

第一步创建接口
BookDao

package com.itheima.dao;

public interface BookDao {
    public void save();
    public void update();
}

第二步:接口实现类
BookDaoImpl

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.stereotype.Repository;

@Repository
public class BookDaoImpl implements BookDao {

    public void save() {
        System.out.println(System.currentTimeMillis());
        System.out.println("BookDao Save...");
    }

    public void update() {
        System.out.println("BookDao Update...");

    }
}

第三步
MyAdvice

package com.itheima.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 MyAdvice {
    @Pointcut("execution(void com.itheima.dao.BookDao.update())")
    private  void pt(){}

    //定义共性功能
    @Before("pt()")
    public void method(){
        System.out.println(System.currentTimeMillis());
    }
}

第四步,配置类加上@EnableAspectJAutoProxy
SpringConfig

package com.itheima.config;

import org.springframework.context.annotation.*;

@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
//@PropertySource("classpath:jdbc.properties")
//@Import(JdbcConfig.class)
public class SpringConfig {
}

第五步
主方法App运行

import com.itheima.config.SpringConfig;
import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao=applicationContext.getBean(BookDao.class);
        bookDao.update();
    }
}

运行结果

1653441242924
BookDao Update...

AOP工作流程 ↓##

SpringAOP本质:代理模式

  1. Spring容器启动

  2. 读取所有切面配置中的切入点

  3. 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
    . 匹配失败,创建对象
    . 匹配成功,创建原始对象(目标对象)的代理对象

  4. 获取bean执行方法
    . 获取bean,调用方法并执行,完成操作
    . 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

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

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

AOP切入点表达式 ↓##

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

AOP通知类型

  1. 前置通知
  2. 后置通知
  3. 环绕通知@Around

在MyAdvice中添加@Around,然后添加ProceedingJoinPoint形参
package com.itheima.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
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 MyAdvice {
    @Pointcut("execution(void com.itheima.dao.BookDao.update())")
    private  void pt(){}

    //定义共性功能
    @Around("pt()")
    public void method(ProceedingJoinPoint proceedingJoinPointn) throws Throwable {
        System.out.println("before");
        proceedingJoinPointn.proceed();
        System.out.println("after");
    }
}

运行结果

before
BookDao Update...
after

4.返回后通知 @AfterReturning
5.抛出异常后通知 @AfterThrowing

AOP通知获取数据##

获取切入点方法的参数
JoinPoint:适用于前置、后置、返回后、抛出异常后通知
ProceedJoinPoint:适用于环绕通知

AOP总结

Spring事务

银行转账事务

SpringMVC

@EnableWebMvc是使用Java 注解快捷配置Spring Webmvc的一个注解。在使用该注解后配置一个继承于WebMvcConfigurerAdapter的配置类即可配置好Spring Webmvc。

通过查看@EnableWebMvc的源码,可以发现该注解就是为了引入一个DelegatingWebMvcConfiguration Java 配置类。并翻看DelegatingWebMvcConfiguration的源码会发现该类似继承于WebMvcConfigurationSupport的类。

其实不使用@EnableWebMvc注解也是可以实现配置Webmvc,只需要将配置类继承于WebMvcConfigurationSupport类即可


## RESTful开发风格 ##

目的是为了隐藏路径中的具体操作,提高安全性,让访问者无法通过路径去辨别你的具体操作

   @RequestMapping(value="/user",method=RequestMethod.POST)
   @ResponseBody
    [方法1]

   @RequestMapping(value="/user1",method=RequestMethod.GET)
   @ResponseBody
    [方法2]

就是利用请求的方法不同,进行的操作也不一样
比如说,localhost:8080/user用POST请求设置为新增用户界面,而用GET请求访问localhost:8080/user则是查询用户。

但是这些只是约定俗成的写法,并不是指定的规范。

若果请求的方法需要一个参数(该参数是从路径中获取),则需要在方法中加上注解@PathVariable,以及在Mapping中加上 {参数名}

@RequestBody、@RequestParam、@PathVariable区别和应用


## 在Controller中,注解上的改进 ## 把@RequestMapping中的value去掉(但是需要参数的要留下来,比如说原来的“/user/{id}”,要把“/ {id}”留下来),一次性加入类头,这样就不用在该类中每个方法都要加上value


类头注解中,@Controller和@RespondBody整合成@RequestController


@RequestMapping中的method.post改为@PostMapping



改进完成后


如果在mvc的默认配置中拦截所有的请求


本应给服务器(比如Tomcat)处理的css和js文件,服务器获取不到

所以应该新增一个配置类,继承WebMvcConfigurationSupport,下图中方法体的含义是:如果有“/pages/**”请求,就访问“/pages/”下的东西(记得被主配置类中扫描到,比如说在该类中添加@Configuration,将该类做成配置类,然后在著配置类中的@ComponentScan添加扫描该类)


# SSM整合 #

配置类思想

SpringConfig


JdbcConfig


MybatisConfig


## ServletConfig(Web容器配置类) ##

其中如果需要过滤器,请参考上面的1507行


SpringMvcConfig


# 项目异常处理 #







前后台协议联调


拦截器

拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
作用:

  1. 在指定方法前后执行预先设置好的代码
  2. 阻止原始方法的执行

拦截器和过滤器的区别 ##:

归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
拦截内容不同:Filter对所有的内容进行增强,Interceptor仅仅针对SpringMVC的访问进行增强





拦截器可以有拦截器链,就是配置多个拦截器。

posted on 2022-07-21 12:05  之火  阅读(35)  评论(0)    收藏  举报