栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SSM框架自学笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SSM框架自学笔记

SSM框架

文章目录
  • SSM框架
    • 一、Spring
      • 1.Spring Framework系统架构
        • Core Container(Spring 的核心容器)
        • Core Container 之上是 AOP、Aspects 等模块
        • Data Access/Integration(数据访问/集成)
        • Web 模块
        • Test 模块
      • 2.Spring核心概念
      • 3.IoC-DI入门案例
      • 4.bean基础配置
      • 5.bean实例化(了解)
      • 6.bean生命周期
        • bean生命周期配置
        • bean生命周期
        • bean销毁时机
      • 7.依赖注入
        • 依赖注入方式
        • 依赖自动装配
        • 集合注入
      • 8.加载properties文件
      • 9.注解开发
        • 注解定义开发bean
        • Bean的管理
        • 依赖注入
        • 第三方bean管理
        • 总结
      • 10.Spring整合MyBatis
        • 创建MyBatis程序
        • 整合MyBatis
      • 11.Spring整合Junit
      • 12.AOP
        • AOP简介
        • AOP入门案例
        • AOP工作流程
        • AOP切入点表达式
          • 语法格式
          • 通配符快速书写
          • 书写技巧
        • AOP通知类型
        • AOP通知获取数据


一、Spring

为什么学?

Spring技术是JavaEE开发必备技能

优点

1.简化开发,降低企业级开发的复杂性

2.框架整合,高效整合其他技术,提高企业级应用开发与应用效率

Spring 是一种基于 Bean 的编程技术,它深刻地改变着 Java 开发世界。Spring 使用简单、基本的 Java Bean 来完成以前只有 EJB 才能完成的工作,使得很多复杂的代码变得优雅和简洁,避免了 EJB 臃肿、低效的开发模式,极大的方便项目的后期维护、升级和扩展。

学什么?

简化开发

IoC

AOP

​ 事务处理

框架整合

Mybatis

MybatisPlus

Struts

Struts2

Hibernate

…


1.Spring Framework系统架构

Core Container(Spring 的核心容器)

Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 SpEL 表达式语言模块组成,没有这些核心容器,也不可能有 AOP、Web 等上层的功能。具体介绍如下。

  • Beans 模块:提供了框架的基础部分,包括控制反转和依赖注入。
  • Core 核心模块:封装了 Spring 框架的底层部分,包括资源访问、类型转换及一些常用工具类。
  • Context 上下文模块:建立在 Core 和 Beans 模块的基础之上,集成 Beans 模块功能并添加资源绑定、数据验证、国际化、Java EE 支持、容器生命周期、事件传播等。ApplicationContext 接口是上下文模块的焦点。
  • SpEL 模块:提供了强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从 Spring 容器获取 Bean,它也支持列表投影、选择和一般的列表聚合等。
Core Container 之上是 AOP、Aspects 等模块

具体介绍如下:

  • AOP 模块:提供了面向切面编程实现,提供比如日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,并且能动态的把这些功能添加到需要的代码中,这样各司其职,降低业务逻辑和通用功能的耦合。
  • Aspects 模块:提供与 AspectJ 的集成,是一个功能强大且成熟的面向切面编程(AOP)框架。
  • Instrumentation 模块:提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用。
  • messaging 模块:Spring 4.0 以后新增了消息(Spring-messaging)模块,该模块提供了对消息传递体系结构和协议的支持。
Data Access/Integration(数据访问/集成)

数据访问/集成层包括 JDBC、ORM、OXM、JMS 和 Transactions 模块,具体介绍如下。

  • JDBC 模块:提供了一个 JBDC 的样例模板,使用这些模板能消除传统冗长的 JDBC 编码还有必须的事务控制,而且能享受到 Spring 管理事务的好处。
  • ORM 模块:提供与流行的“对象-关系”映射框架无缝集成的 API,包括 JPA、JDO、Hibernate 和 MyBatis 等。而且还可以使用 Spring 事务管理,无需额外控制事务。
  • OXM 模块:提供了一个支持 Object /XML 映射的抽象层实现,如 JAXB、Castor、XMLBeans、JiBX 和 XStream。将 Java 对象映射成 XML 数据,或者将XML 数据映射成 Java 对象。
  • JMS 模块:指 Java 消息服务,提供一套 “消息生产者、消息消费者”模板用于更加简单的使用 JMS,JMS 用于用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
  • Transactions 事务模块:支持编程和声明式事务管理。
Web 模块

Spring 的 Web 层包括 Web、Servlet、WebSocket 和 Portlet 组件,具体介绍如下。

  • Web 模块:提供了基本的 Web 开发集成特性,例如多文件上传功能、使用的 Servlet 监听器的 IOC 容器初始化以及 Web 应用上下文。
  • Servlet 模块:提供了一个 Spring MVC Web 框架实现。Spring MVC 框架提供了基于注解的请求资源注入、更简单的数据绑定、数据验证等及一套非常易用的 JSP 标签,完全无缝与 Spring 其他技术协作。
  • WebSocket 模块:提供了简单的接口,用户只要实现响应的接口就可以快速的搭建 WebSocket Server,从而实现双向通讯。
  • Portlet 模块:提供了在 Portlet 环境中使用 MVC 实现,类似 Web-Servlet 模块的功能。
Test 模块

Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。


2.Spring核心概念
  • IoC(Inversion of Control)控制反转

    • 使用对象时,由主动new对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想成为控制反转。
  • Spring技术对IoC思想进行了实现

    • Spring提供了一个容器,成为IoC容器,用来充当IoC思想中的“外部”

    • IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中成为Bean

  • DI(Dependency Injection)依赖注入

    • 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gzObKs77-1657903752356)(C:UserszcyDesktopIoC容器.png)]


3.IoC-DI入门案例
  1. 导入spring坐标spring-context,对应的版本5.2.10.RELEASE

    
        org.springframework
        spring-context
        5.2.10.RELEASE
    
    
  2. 配置bean

    
    
    
  3. 获取IoC容器

    ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
    
  4. 获取Bean

    BookDao bookBao = (BookDao)ctx.getBean("bookDao");
    
  5. 删除业务层中使用new创建的dao对象

    private BookDao bookDao;
    
  6. 提供对应的set方法

    public void setBookDao(BookDao bookDao) {
            this.bookDao = bookDao;
        }
    
  7. 配置service与dao的关系

    
    
    
            
    
    

4.bean基础配置

在 XML 配置的 元素中可以包含多个属性或子元素,常用的属性或子元素如下表所示。

属性名称描述
idBean 的唯一标识符,Spring IoC 容器对 Bean 的配置和管理都通过该属性完成。id 的值必须以字母开始,可以使用字母、数字、下划线等符号。
name该属性表示 Bean 的名称,我们可以通过 name 属性为同一个 Bean 同时指定多个名称,每个名称之间用逗号或分号隔开。Spring 容器可以通过 name 属性配置和管理容器中的 Bean。
class该属性指定了 Bean 的具体实现类,它必须是一个完整的类名,即类的全限定名。
scope表示 Bean 的作用域,属性值可以为 singleton(单例)、prototype(原型)、request、session 和 global Session。默认值是 singleton。
constructor-arg 元素的子元素,我们可以通过该元素,将构造参数传入,以实现 Bean 的实例化。该元素的 index 属性指定构造参数的序号(从 0 开始),type 属性指定构造参数的类型。
property元素的子元素,用于调用 Bean 实例中的 setter 方法对属性进行赋值,从而完成属性的注入。该元素的 name 属性用于指定 Bean 实例中相应的属性名。
ref 和 等元素的子元索,用于指定对某个 Bean 实例的引用,即 元素中的 id 或 name 属性。
value 和 等元素的子元素,用于直接指定一个常量值。
list用于封装 List 或数组类型的属性注入。
set用于封装 Set 类型的属性注入。
map用于封装 Map 类型的属性注入。
entry 元素的子元素,用于设置一个键值对。其 key 属性指定字符串类型的键值,ref 或 value 子元素指定其值。
init-method容器加载 Bean 时调用该方法,类似于 Servlet 中的 init() 方法
destroy-method容器删除 Bean 时调用该方法,类似于 Servlet 中的 destroy() 方法。该方法只在 scope=singleton 时有效
lazy-init懒加载,值为 true,容器在首次请求时才会创建 Bean 实例;值为 false,容器在启动时创建 Bean 实例。该方法只在 scope=singleton 时有效

5.bean实例化(了解)

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

  1. 构造方法

    public BookDaoImpl() {
            System.out.println("book dao constructor is running");
        }
    
    
    
    
  2. 静态工厂

    public class OrderDaoFactory {
        public static OrderDao getOrderDao(){
            return new OrderDaoImpl();
        }
    }
    
    
    
    
  3. 实例工厂创建对象

    public class UserDaoFactory {
        public UserDao getUserDao(){
            return new UserDaoImpl();
        }
    }
    
    
    
    
    

    改良版

    public class UserDaoFactoryBean implements FactoryBean {
        //代替原始实例工厂中创建对象的方法
        public UserDao getObject() throws Exception {
            return new UserDaoImpl();
        }
    	//获取bean类型
        public Class getObjectType() {
            return UserDao.class;
        }
        //设置单例非单例
        public boolean isSingleton() {
            return true;
        }
    }
    
    
        
    

6.bean生命周期 bean生命周期配置
  1. 使用配置生命周期

    bean创建之前:init()

    bean销毁之后:destroy()

    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println("book dao save");
        }
    
        public void init(){
            System.out.println("init...");
        }
        public void destroy(){
            System.out.println("destroy...");
        }
    }
    
    
    
    public static void main(String[] args) {
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    
            bookDao.save();
        	ctx.registerShutdownHook();//关闭钩子
    //        ctx.close();//要看到destroy要关闭容器比较暴力
        }
    
  2. 使用接口控制生命周期

    实现InitializingBean, DisposableBean接口

    public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
        private BookDao bookDao;
    
        public void setBookDao(BookDao bookDao) {
            this.bookDao = bookDao;
        }
    
        public void save() {
            System.out.println("book service save");
        }
    
        public void destroy() throws Exception {
            System.out.println("service destroy...");
        }
    
        public void afterPropertiesSet() throws Exception {
            System.out.println("afterPropertiesSet...");
        }
    }
    
    
            
        
    
    public static void main(String[] args) {
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    
            bookDao.save();
    //    	ctx.registerShutdownHook();//关闭钩子
    	    ctx.close();//要看到destroy要关闭容器比较暴力
        }
    
bean生命周期

初始化容器

  1. 创建容器(内存分配)
  2. 执行构造方法
  3. 执行属性注入(set)
  4. 执行bean初始化方法

使用bean

  1. 执行业务操作

关闭/销毁容器

  1. 执行bean销毁方法
bean销毁时机

容器关闭前触发bean的销毁

关闭容器方式

  1. 手工关闭容器

    ConfigurableApplicationContext接口close()方法

  2. 注册关闭钩子,在虚拟机推出前先关闭容器再退出虚拟机

    ConfigurableApplicationContext接口registerShutdownHook()操作


7.依赖注入 依赖注入方式

setter注入

​ 简单类型

​ 引用类型

构造器注入

​ 简单类型

​ 引用类型

  1. setter注入——引用类型

    在bean中定义引用类型属性,并提供可访问的set方法

    配置中使用property标签ref属性注入引用类型对象

  2. setter注入——简单类型

    在bean中定义引用类型属性并提供可访问的set方法

    配置中使用property标签value属性注入简单类型数据

  3. 构造器注入——引用类型

    在bean中定义引用类型属性并提供可访问的构造方法

    配置中使用constructor-arg标签ref属性注入引用类型对象

  4. 构造器注入——简单类型

    在bean中定义引用类型属性并提供可访问的构造方法

    配置中使用constructor-arg标签value属性注入简单类型数据

依赖注入方式的选择

  1. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
  2. 可选依赖使用setter注入进行,灵活性强
  3. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
  4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
  5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
  6. 自己开发的模块推荐使用settet注入
依赖自动装配

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

自动装配方式

  • 按类型
  • 按名称
  • 按构造方法
  • 不启用自动装配

配置中使用bean标签autowire属性设置自动装配的类型

特征

  1. 自动装配用于引用类型的依赖注入,不能对简单类型进行操作
  2. 使用按类型装配时(byType)必须保障容器中相同类型bean唯一,推荐使用
  3. 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
  4. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配失效
集合注入
  • 数组
  • List
  • Set
  • Map
  • Properties

        
            
                100
                200
                300
                400
            
        
        
            
                itcast
                haust
                heima
                400
            
        
        
            
                itcast
                haust
                heima
                haust
            
        
        
            
                
                
                
            
        
        
            
                china
                henan
                zhengzhou
            
        
    

8.加载properties文件

​ 提前准备properties文件

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url="jdbc:mysql://localhost:3306/spring_db"
jdbc.username="root"
jdbc.password="root"
  1. 开辟新的命名空间context

    
    
  2. 使用命名空间context加载properties文件

    
    
    • 不加载系统属性

      
      
    • 加载多个properties文件

      
      
    • 加载所有properties文件

      
      
    • 加载properties文件标准格式

      
      
    • 从类路径或jar包中搜索并加载properties文件

      
      
  3. 使用属性占位符${}读取properties文件的属性

    
            
            
            
            
        
    

9.注解开发 注解定义开发bean
  1. 使用@Component定义bean

    @Component
    public class BookServiceImpl implements BookService {
    }
    @Component("bookDao")
    public class BookDaoImpl implements BookDao {
    }
    
  2. 核心配置文件中通过组件扫描加载bean

    
    

    Spring提供@Component注解的三个衍生注解

    • @Controller:用于表现层bean定义
    • @Service:用于业务层bean定义
    • @Repository:用于数据层bean定义

在Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道

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

@Configuration:用于设置当前类为配置类

@ComponentScan:用于设定扫描路径,此注解只能添加一次,多个数据请求用数组格式

注意:读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器

ApplicationContext ctx=new AnnotationConfigApplicationContext(SpringConfig.class);
Bean的管理
  1. bean的作用范围

    控制单例非单例

    @Scope("prototype")
    
  2. bean的生命周期

    @PostConstruct
    public void init() {
        System.out.println("init...");
    }
    
    @PreDestroy
    public void destroy() {
        System.out.println("destroy...");
    }
    
依赖注入

自动装配

@Autowired

@Qualifier

@Value

@PropertySource

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    @Qualifier("bookDao")
    private BookDao bookDao;

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

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    @Value("${name}")
    private String name;
    @Override
    public void save() {
        System.out.println("book dao save..."+name);
    }
}
@Configuration
@ComponentScan("com.itheima")
@PropertySource("jdbc.properties")
public class SpringConfig {
}
  • 自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法
  • 自动装配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法
  • 使用@Qualifier注解开启指定名称装配bean,无法单独使用,必须配合@Autowired注解使用
  • 使用@PropertySource注解加载properties文件,路径仅支持单一文件配置,多文件使用数组格式配置,不允许使用通配符*
第三方bean管理

使用@Bean配置第三方bean,使用独立的配置类加入核心配置

使用@Import注解手动加入配置类到核心配置,此注解只能添加一次,多个数据用数组格式

//1.定义一个方法获得要管理的对象
    //2.添加@bean表示当前方法的返回值是一个bean
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds=new DruidDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
@Import({JdbcConfig.class})

简单类型依赖注入:成员变量

引用类型依赖注入:方法形参

public class JdbcConfig {
    @Value("${jdbc.driver}")
    private  String driver;
    @Value("${jdbc.url}")
    private  String url;
    @Value("${jdbc.username}")
    private  String username;
    @Value("${jdbc.password}")
    private  String password;
    //1.定义一个方法获得要管理的对象
    //2.添加@bean表示当前方法的返回值是一个bean
    @Bean
    public DataSource dataSource(BookDao bookDao){
        System.out.println(bookDao);
        DruidDataSource ds=new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        return ds;
    }
}
总结

xml配置与注解配置

功能XML配置注解
定义beanbean标签:id属性,class属性@Component;@Controller;@Service;@Repository;@ComponentScan
设置依赖注入setter注入(set方法)1.引用/简单:构造器注入2.引用/简单:自动装配@Autowired;@Qualifier;@Value
配置第三方beanbean标签:静态工厂、实例工厂、FactoryBean@Bean
作用范围scope属性@Scope
生命周期标准接口:init-method、destroy-method@PostConstruct;@PreDestroy

10.Spring整合MyBatis 创建MyBatis程序

pom.xml文件中的依赖


        
        
            org.mybatis
            mybatis
            3.5.7
        
        
            mysql
            mysql-connector-java
            8.0.16
        
        
            org.springframework
            spring-context
            5.2.10.RELEASE
            compile
        

SqlMapConfig.xml配置文件





    

    
        
    

    
        
            
            
                
                
                
                
            
        
    

    
        
    

jdbc.properties文件

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false
jdbc.username=root
jdbc.password=root

dao

package com.itheima.dao;

import com.itheima.domain.Account;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

public interface AccountDao {
    @Insert("insert into tbl_account(name,money) values(#{name},#{money})")
    void save(Account account);

    @Delete("delete from tbl_account where id=#{id}")
    void delete(Integer id);

    @Update("update tbl_account set name=#{name},money=#{money} where id=#{id}")
    void update(Account account);

    @Select("select * from tbl_account")
    List findAll();

    @Select("select * from tbl_account where id=#{id}")
    Account findById(Integer id);
}

主程序

public class App {
    public static void main(String[] args) throws IOException {
        //1.创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //2.加载SqlMapConfig.xml配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //3.创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);
        //4.获取SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //5.执行SqlSession对象执行查询获取结果User
        AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
        Account account = accountDao.findById(1);
        System.out.println(account);
        sqlSession.close();
    }
}

整合MyBatis

SqlSessionFactoryBean

MapperScannerConfigurer

1.添加所需要的依赖


            org.springframework
            spring-jdbc
            5.2.10.RELEASE


            org.mybatis
            mybatis-spring
            1.3.0


            com.alibaba
            druid
            1.1.6

2.添加配置类

  • SpringConfig

    package com.itheima.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    import org.springframework.context.annotation.PropertySource;
    
    @Configuration
    @ComponentScan("com.itheima")
    @PropertySource("jdbc.properties")
    @Import({JdbcConfig.class,MyBatisConfig.class})
    public class SpringConfig {
    }
    
  • JdbcConfig

    package com.itheima.config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    
    import javax.sql.DataSource;
    
    public class JdbcConfig {
        @Value("${jdbc.driver}")
        private  String driver;
        @Value("${jdbc.url}")
        private  String url;
        @Value("${jdbc.username}")
        private  String username;
        @Value("${jdbc.password}")
        private  String password;
    
        @Bean
        public DataSource dataSource(){
            DruidDataSource ds=new DruidDataSource();
            ds.setDriverClassName(driver);
            ds.setUrl(url);
            ds.setUsername(username);
            ds.setPassword(password);
            return ds;
        }
    }
    
  • MyBatisConfig

    package com.itheima.config;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.mapper.MapperScannerConfigurer;
    import org.springframework.context.annotation.Bean;
    
    import javax.sql.DataSource;
    
    public class MyBatisConfig {
        @Bean
        public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
            SqlSessionFactoryBean ssfb=new SqlSessionFactoryBean();
            ssfb.setTypeAliasesPackage("com.itheima.domain");
            ssfb.setDataSource(dataSource);
            return ssfb;
        }
        @Bean
        public MapperScannerConfigurer mapperScannerConfigurer(){
            MapperScannerConfigurer msc = new MapperScannerConfigurer();
            msc.setBasePackage("com.itheima.dao");
            return msc;
        }
    }
    

3.主程序

public class App2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        AccountService accountService = ctx.getBean(AccountService.class);
        Account account = accountService.findById(1);
        System.out.println(account);
    }
}

11.Spring整合Junit

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)

1.添加所需的依赖


            junit
            junit
            4.12
            test


            org.springframework
            spring-test
            5.2.10.RELEASE

2.类加载器

package com.itheima.service;

import com.itheima.config.SpringConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
    @Autowired
    private AccountService accountService;

    @Test
    public void testFindById(){
        System.out.println(accountService.findById(2));
    }
}


12.AOP AOP简介

AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构

作用:在不惊动原始设计的基础上为其进行功能增强

Spring理念:无入侵式

  • 连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法,抛出异常,设置变量等
    • 在SpringAOP中,理解为方法的执行
  • 切入点(PointCut):匹配连接点的式子
    • 在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
    • 一个具体方法:com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
    • 匹配多个方法:所有的save方法,所有get开头的方法,所有Dao结尾的接口中的任意方法,所有带一个参数的方法
  • 通知(Advice):在切入点处执行的操作,也就是共性功能
    • 在SpringAOP中,功能最终以方法的形式呈现
  • 通知类:定义通知的类
  • 切面(Aspect):描述通知与切入点的对应关系
AOP入门案例

1.导入坐标


    org.springframework
    spring-context
    5.2.10.RELEASE
    compile


    org.aspectj
    aspectjweaver
    1.9.4

2.制作连接点方法(原始操作,Dao接口与实现类)

public interface AccountService {
    void save(Account account);

    void delete(Integer id);

    void update(Account account);

    List findAll();

    Account findById(Integer id);
}

3.制作共性功能(通知类与通知)

public class ProjectAdvice {
    public void runSpeed()  {
        System.out.println("111");
    }
}

4.定义切入点

public class ProjectAdvice {
    @Pointcut("execution(* com.itheima.service.*Service.*(..))")
    private void servicePt(){};
}

5.绑定切入点与通知关系

@Component
@Aspect
public class ProjectAdvice {
    @Pointcut("execution(* com.itheima.service.*Service.*(..))")
    private void servicePt(){};
    
	@Before("servicePt()")
    public void runSpeed()  {
        System.out.println("111");
    }
}

6.开启Spring对AOP注解驱动支持

@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {
}
AOP工作流程

1.启动Spring容器

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

3.初始化bean,判定bean对应的类中的方法是否匹配到任意切入点

  • 匹配失败,创建对象
  • 匹配成功,创建原始对象(目标对象)的代理对象

4.获取bean执行方法

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

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

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

AOP切入点表达式 语法格式

切入点表达式标准格式:动作关键字(访问修饰符 返回值 百名.类/接口名.方法(参数) 异常名)

execution(public User com.itheima.service.UserService.findById(int))
通配符快速书写

可以通过通配符描述切入点,快速描述

  1. *:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现

    execution(public * com.itheima.*.UserService.find*(*))
    

    匹配com.itheima包下任意包中的UserService类或接口中所有find开头的带有一个参数的方法

  2. …:多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写

    execution(public User com..UserService.findById(..))
    

    匹配com包下的任意 包中的UserService类或接口中的所有名称为fingById的方法

  3. +:专用于匹配子类类型

    execution(* *..*Service+.*(..))
    
书写技巧
  • 所有代码按照标准规范开发,否则以下技巧全部失效
  • 描述切入点通常描述接口,而不描述实现类
  • 访问控制修饰符针对接口开发均采用public描述(可省略访问控制修饰符描述)
  • 返回值类型对于增删改类使用精准类型加速匹配,对于查询类使用*通配快速描述*
  • 包名书写尽量不使用…匹配,效率过低,常用做单个包描述匹配,或精准匹配
  • 接口名/类名书写名称与模块相关的采用*匹配,例如UserService书写成*Service,绑定业务层接口名
  • 方法名书写以动词进行精准匹配,名词采用*匹配,例如getByld书写成getBy*,selectAll书写成selectAll
  • 参数规则较为复杂,根据业务方法灵活调整
  • 通常不使用异常作为匹配规则
AOP通知类型

AOP通知描述了抽取的共性功能,根据共性功能抽取的位置不同,最终运行代码时要将其加入到合理的位置

AOP通知共分为5种类型

  • 前置通知@Before(“fn()”)

  • 后置通知@After(“fn()”)

  • 环绕通知(重点)@Around(“fn()”)

        @Around("ProjectAdvice.servicePt()")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            Object ret = pjp.proceed();
            System.out.println("我是新增的");
            return ret;
        }
    

    @Around注意事项

    1.环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加同时

    2.通知中如果未使用ProceedingPoint对原始方法进行调用,将跳过原始方法的执行(可以进行权限校验)

    3.对原始方法的调用不可以不接收返回值,通知方法设置成void即可,如果接收返回值,必须设定为Object类型

    4.原始方法的返回值如果是void类型,通知方法返回值类型可以设置成void,也可以设置成Object

    5.由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象

  • 返回后通知(了解)@AfterReturning(“fn()”)

  • 抛出异常后通知(了解)@AfterThrowing(“fn()”)

AOP通知获取数据
  • 获取切入点方法的参数

    • JoinPoint:适用于前置、后置、返回后、抛出异常后通知

      JoinPoint.getArgs();
      
    • ProceedJoinPoint:适用于环绕通知

      pjp.getArgs();
      
  • 获取切入点方法返回值

    • 返回后通知
    • 环绕通知
  • 获取切入点方法运行异常信息

    • 抛出异常后通知
    • 环绕通知
  • 获取切入点方法运行异常信息

  • 抛出异常后通知

  • 环绕通知

签名信息

//获取执行签名信息
Signature signature = pjp.getSignature();
//通过签名获取执行类型(接口名)
String className=signature.getDeclaringTypeName();
//通过签名获取执行操作名称(方法名)
String mothodName=signature.getName();
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1024533.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号