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版)
- 基于上面的IoC管理bean
- Service中使用new的形式不能保留
- Service中需要的Dao对象如何进入到Service中?提供方法
- 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的配置↓
别名
- bean标签可以用name来设置别名,可以用逗号、分号或者空格来隔开设置多个别名
- 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的属性:
- "prototype"非单例
- "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生命周期。
依赖注入↓
思考:向一个类中传递数据的方式有几种?
- 普通set方法
- 构造方法
依赖注入描述了在容器中建立bean和bean之间依赖关系的过程,如果bean运行需要的是数字或者字符串呢?
- 引用类型
- 简单类型(基本数据类型与String
依赖注入的方式
-
setter注入
简单类型
引用类型 -
构造器注入
简单类型
引用类型
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属性必须和类中形参一致,形参要是改名配置也要改名,这样耦合度太高,解决方法
-
使用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> -
使用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本质:代理模式
-
Spring容器启动
-
读取所有切面配置中的切入点
-
初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
. 匹配失败,创建对象
. 匹配成功,创建原始对象(目标对象)的代理对象 -
获取bean执行方法
. 获取bean,调用方法并执行,完成操作
. 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作
目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法完成最终工作的
代理(Proxy):目标对象无法直接完成工作,需要对其进行回填,通过原始对象的代理对象实现
AOP切入点表达式 ↓##
切入点:需要增强的方法
切入点表达式:要进行增强的方法的描述方式

AOP通知类型
- 前置通知
- 后置通知
- 环绕通知@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中动态拦截控制器方法的执行
作用:
- 在指定方法前后执行预先设置好的代码
- 阻止原始方法的执行
拦截器和过滤器的区别 ##:
归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
拦截内容不同:Filter对所有的内容进行增强,Interceptor仅仅针对SpringMVC的访问进行增强





拦截器可以有拦截器链,就是配置多个拦截器。
浙公网安备 33010602011771号