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里面添加坐标



4.0.0

org.example
spring01
pom
1.0-SNAPSHOT



org.springframework
spring-context
5.2.10.RELEASE


junit
junit
4.13


新建一个applicationContext.xml




主方法里面

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之间的关系







在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属性







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

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();
}
}
配置类修改



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

配置类





先把工厂的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 {
//代替原始实例工厂中创建对象的方法
public OrderDao getObject() throws Exception {
return new OrderDaoImpl();
}

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



运行结果:

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 {
//代替原始实例工厂中创建对象的方法
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属性




因为配置类中的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();
}
}

配置类








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设置值










运行结果:

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,让他们形成依赖。










运行结果:

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结合传参数










运行结果:

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

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

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




  2. 使用index,根据索引去找,不过要注意顺序




依赖自动装配↓

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



在实现类中提供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 list;
private Set set;
private Map<String, String> map;
private Properties properties;

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

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

public void setSet(Set 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);
}

}

配置类





100
200
300




suyang
xingxing




10000
30000
50000
40000











mieba
huanshi
nvwu


运行结果:

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

数据源对象管理 ↓##

先在pom.xml添加坐标


com.alibaba
druid
1.1.24


c3p0
c3p0
0.9.1.2


mysql
mysql-connector-java
8.0.21

Druid


·






c3p0






加载properties文件

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

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

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



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








通过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

配置类



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

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代替了


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

@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


4.0.0
org.example
SpringAndMybatis
jar
1.0-SNAPSHOT
Maven Quick Start Archetype
http://maven.apache.org


org.springframework
spring-context
5.3.20


org.aspectj
aspectjweaver
1.9.6


第一步创建接口
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  之火  阅读(41)  评论(0)    收藏  举报