ssm框架 一、spring 1.1 Spring Framework系统架构 Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基
Data Access: 数据访问
Data Integration: 数据集
Web: Web开发
AOP:面向切面编程
Aspects: AOP思想实现
Core Container: 核心容器
Test:单元测试与集成测试
1.2 核心概念
IoC具体实现:
导入spring坐标,新建spring配置文件applicationContext.xml
在配置文件中配置bean
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id = "bookDao" class ="org.example.dao.impl.BookDaoImpl" /> <bean id = "bookService" class ="org.example.service.impl.BookServiceImpl" /> </beans >
获取Ioc容器
获取bean
1 2 3 4 5 6 7 8 9 10 11 public class App2 { public static void main (String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext ("applicationContext.xml" ); BookDao bookDao = (BookDao) ctx.getBean("bookDao" ); BookService bookService = (BookService) ctx.getBean("bookService" ); bookService.save(); } }
DI具体实现:
1.删除业务层中new创建的dao对象
2.提供对应的set方法
3.配置dao与service的关系
1 2 3 4 5 6 7 8 <bean id = "bookDao" class ="org.example.dao.impl.BookDaoImpl" /> <bean id = "bookService" class ="org.example.service.impl.BookServiceImpl" > <property name ="bookDao" ref ="bookDao" /> </bean >
1.3 XML-bean配置
使用name属性配置别名,多个别名使用空格隔开
1 <bean id = "bookDao" name ="bookDao2 bookDao3" class ="org.example.dao.impl.BookDaoImpl" />
spring创建的bean默认为单例,使用scope属性配置,singleton(单例),prototype(非单例)
适合交给容器进行管理的bean
不适合交给容器进行管理的bean
1.4 XML-bean实例化
方法一:构造方法实例化bean
bean本质上就是对象,实例化就是调用的无参构造方法(无论是public还是private)
方法二:使用静态工厂实例化bean
静态工厂:
1 2 3 4 5 public class OrderDaoFactory { public static OrderDao getOrderDao () { return new OrderDaoImpl (); } }
配置:
1 <bean id ="orderDao" class ="org.example.factory.OrderDaoFactory" factory-method ="getOrderDao" />
方法三:实例工厂实例化bean
实例工厂:
1 2 3 4 5 public class UserDaoFactory { public UserDao getUserDao () { return new UserDaoImpl (); } }
配置:
1 2 <bean id ="userDaoFactory" class ="org.example.factory.UserDaoFactory" /> <bean id ="userDao" factory-bean ="userDaoFactory" factory-method ="getUserDao" />
方法四 :使用factoryBean实例化(方法三改良)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class UserDaoFactoryBean implements FactoryBean <UserDao> { @Override public UserDao getObject () throws Exception { return new UserDaoImpl (); } @Override public Class<?> getObjectType() { return UserDao.class; } } @Override public boolean isSingleton () { return FactoryBean.super .isSingleton(); }
配置:
1 <bean id ="userDao" class ="org.example.factory.UserDaoFactoryBean" />
1.5 XML-bean生命周期
提供生命周期控制方法,并写好配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class BookDaoImpl implements BookDao { private BookDaoImpl () { System.out.println("bookDaoImpl constructor is running ..." ); } @Override public void save () { System.out.println("book dao save ..." ); } public void init () { System.out.println("init book dao ..." ); } public void destory () { System.out.println("destory book dao ..." ); } }
配置:
使用init-method、destory-method属性配置
1 <bean id = "bookDao" name ="bookDao2 bookDao3" class ="org.example.dao.impl.BookDaoImpl" init-method ="init" destroy-method ="destory" />
使用spring提供的接口控制生命周期
实现InitializingBean, DisposableBean接口,实现方法destory()、afterPropertiesSet()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class BookServiceImpl implements BookService , InitializingBean, DisposableBean { private BookDao bookDao; @Override public void save () { System.out.println("book service save ..." ); bookDao.save(); } public void setBookDao (BookDao bookDao) { this .bookDao = bookDao; } @Override public void destroy () throws Exception { System.out.println("destroy book service destroy" ); } @Override public void afterPropertiesSet () throws Exception { System.out.println("init book service afterPropertiesSet" ); } }
1.6 XML-依赖注入方式(DI)
setter注入(简单类型,引用类型)
写好简单类型的set方法
在配置文件中,bean标签中使用property标签,配置property标签的name属性(与简单类型相同)与value属性(要提供的值)
写好引用类型的set方法
在配置文件中,bean标签中使用property标签,配置property标签的name属性(与简单类型相同)与ref属性(参照bean的名称)
1 2 3 4 5 6 7 8 9 10 11 12 <bean id = "bookDao" name ="bookDao2 bookDao3" class ="org.example.dao.impl.BookDaoImpl" > <property name ="databaseName" value ="mysql" > </property > <property name ="connectionNumber" value ="10" > </property > </bean > <bean id = "bookService" class ="org.example.service.impl.BookServiceImpl" > <property name ="bookDao" ref ="bookDao" /> </bean >
构造方法注入(简单类型、引用类型)
使用构造器传参,在constructor-arg标签中配置name(与构造器形参一致)、value属性
使用构造器传参,在constructor-arg标签中配置name(与构造器形参一致)、ref属性
1 2 3 4 5 6 7 8 9 <bean id = "bookDao" name ="bookDao2 bookDao3" class ="org.example.dao.impl.BookDaoImpl" > <constructor-arg name ="connectionNumber" value ="10" /> <constructor-arg name ="databaseName" value ="mysql" /> </bean > <bean id = "bookService" class ="org.example.service.impl.BookServiceImpl" > <constructor-arg name ="bookDao" ref ="bookDao" > </constructor-arg > </bean >
解耦合改良:
使用type属性表示形参
使用index属性表示形参
1.7 XML-依赖自动装配(引用类型)
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
自动装配方式
按类型(常用)
按名称
按构造方法
不启用自动装配
1 <bean id = "bookService" class ="org.example.service.impl.BookServiceImpl" autowire ="byType" >
1.8 XML-集合注入
集合
标签
array
property嵌array嵌value(ref)
list
property嵌list嵌value(ref)
set
property嵌set嵌value(ref)
map
property嵌map嵌entry
property
property嵌props嵌prop
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <bean id = "bookDao" name ="bookDao2 bookDao3" class ="org.example.dao.impl.BookDaoImpl" > <property name ="array" > <array > <value > 10</value > <value > 20</value > <value > 30</value > <value > 40</value > </array > </property > <property name ="list" > <list > <value > wei</value > <value > kkk</value > <value > yang</value > </list > </property > <property name ="set" > <set > <value > hahh</value > <value > jjj</value > <value > jjj</value > </set > </property > <property name ="map" > <map > <entry key ="wei" value ="666" /> <entry key ="si" value ="66" /> </map > </property > <property name ="properties" > <props > <prop key ="country" > china</prop > <prop key ="province" > jiangsu</prop > </props > </property > </bean >
1.9 XML-管理数据源对象 1 2 3 4 5 6 7 8 9 10 11 12 13 <bean id ="dataSource1" class ="com.alibaba.druid.pool.DruidDataSource" > <property name ="driverClassName" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/3306" /> <property name ="username" value ="root" /> <property name ="password" value ="weisiyang" /> </bean > <bean id ="dataSource" class ="com.mchange.v2.c3p0.ComboPooledDataSource" > <property name ="driverClass" value ="com.mysql.jdbc.Driver" /> <property name ="jdbcUrl" value ="jdbc:mysql://localhost:3306/3306" /> <property name ="user" value ="root" /> <property name ="password" value ="weisiyang" /> </bean >
1.9 XML-加载properties文件
开启context命名空间
1 2 3 4 5 6 7 <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:context ="http://www.springframework.org/schema/context" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:util ="http://www.springframework.org/schema/util" xsi:schemaLocation =" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context " >
2.加载properties文件,多个文件location中用,隔开
1 <context:property-placeholder location ="jdbc.properties" />
常用格式:
1 <context:property-placeholder location ="classpath*:*.properties" />
3.使用属性占位符${}读取文件中的属性-
1 2 3 4 5 6 <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" > <property name ="driverClassName" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> </bean >
1.10 容器
创建容器
获取bean
容器类层次结构图
2.1 注解开发
使用@component定义bean
1 2 3 @Component public class BookDaoImpl implements BookDao {}
核心配置文件中通过组件扫描加载bean
1 <context:component-scan base-package ="org.example" />
component衍生注解
2.2 纯注解开发
使用@Configuration注解设置当前类为配置类
使用@ComponentScan注解设定扫描路径,多个数据用数组格式
1 2 3 4 @Configuration @ComponentScan({"org.example.dao","org.example.service"}) public class SpringConfig {}
加载配置类初始化容器
1 2 ApplicationContext ctx = new AnnotationConfigApplicationContext (SpringConfig.class);
2.3 注解开发-bean管理
bean作用范围
使用@Scope注解设定某个类
1 2 @Scope("singleton") @Scope("prototype")
2.bean生命周期
使用@PostConstruct注解设定某个类中的方法为构造方法后初始化方法
1 2 3 4 @PostConstruct public void init () { System.out.println("book init ..." ); }
使用@PreDestory注解设定某个类中的方法为销毁前方法
1 2 3 4 @PreDestroy public void destroy () { System.out.println("book destroy ..." ); }
2.4 注解开发-依赖注入
引用类型:自动装配
使用@Autowired注解设置引用类型自动装配,默认为按类型 装配,
可使用@Qualifier注解设置按名称 装配(要为配装配的类设置称)
1 2 3 @Autowired @Qualifier("bookDao2") private BookDao bookDao;
简单类型
1 2 @Value("13") private int a;
2.5 注解开发-第三方bean管理、依赖注入
第三方bean管理
在配置类中定义一个方法用于获取数据源对象,为该方法添加@Bean注解
1 2 3 4 5 6 7 8 9 10 11 public class SpringConfig { @Bean DataSource dataSource () { DruidDataSource ds = new DruidDataSource (); ds.setDriverClassName("${jdbc.driverClassName}" ); ds.setUrl("${jdbc.url}" ); ds.setUsername("${jdbc.username}" ); ds.setPassword("${jdbc.password}" ); return ds; } }
获取数据源对象:
1 2 3 4 5 6 7 8 9 public class App { public static void main ( String[] args ) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext (SpringConfig.class); DataSource dataSource = (DataSource)context.getBean(DataSource.class); System.out.println(dataSource); } }
改良:新建单独配置类,在主配置类中使用@Import(className.Class)导入该类(导入多个类使用数组形式 )
1 2 3 4 5 6 7 8 9 10 11 public class JdbcConfig { @Bean DataSource dataSource () { DruidDataSource ds = new DruidDataSource (); ds.setDriverClassName("${jdbc.driverClassName}" ); ds.setUrl("${jdbc.url}" ); ds.setUsername("${jdbc.username}" ); ds.setPassword("${jdbc.password}" ); return ds; } }
1 2 3 4 5 6 7 8 @Configuration @ComponentScan({"org.example.dao","org.example.service"}) @PropertySource("jdbc.properties") @Import(JdbcConfig.class) public class SpringConfig {}
依赖注入
1 2 3 4 5 6 7 8 9 @Value("${jdbc.driverClassName}") private String className;@Value("${jdbc.url}") private String url;@Value("${jdbc.username}") private String username;@Value("${jdbc.password}") private String password;@Bean
作为形参会自动装配(按类型 )
1 2 3 4 5 6 7 8 9 10 11 @Bean DataSource dataSource (BookDao bookDao) { System.out.println(bookDao); DruidDataSource ds = new DruidDataSource (); ds.setDriverClassName(className); ds.setUrl(url); ds.setUsername(username); ds.setPassword(password); return ds; }
3. XML与注解开发对比
二、Spring整合 1.1Spring整合MyBatis
导入依赖坐标
1 2 3 4 5 6 7 8 9 10 11 12 <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.6</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 1.3.0</version > </dependency >
与sqlsessionFactory有关的配置转换成sqlSessionFactory方法来配置
mapper映射转换成Mybatis配置类中MapperScannerConfiguer方法
1.2 Spring整合Junit
导入依赖坐标
1 2 3 4 5 6 7 8 9 10 11 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-test</artifactId > <version > 5.2.10.RELEASE</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > test</scope > </dependency >
设置类加载器(SpringJunit4ClassRunner),设置spring上下文配置(SpringContext)
1 2 3 4 5 6 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class AccountServiceTest {}
进行测试
1 2 3 4 5 6 7 8 9 10 public class AccountServiceTest { @Autowired private AccountService accountService; @Test public void TestAccountService () { System.out.println(accountService.findById(1 )); } }
三 AOP 1.1 AOP简介
AOP(Aspect Oriented Programming) 面向切面编程,一种编程范式 ,指导开发者如何组织程序结构
00P(Object 0riented Progr amming)面向对象编程
作用:在不惊动原始设计的基础上为其进行功能增强
Spring理念:无入侵式/无侵入式
核心概念:
连接点( JoinPoint ) : 程序执行过程中的任意位置, 粒度为执行方法、抛出异常、设置变量等
切入点( Pointcut ) : 匹配连接点的式子(切入点<连接点)
在SpringAOP中 , -个切入点可以只描述一个具体方法,也可以匹配多个方法
一个具体方法: com. itheima . dao包下的BookDao接口中的无形参无返回值的save方法
匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有-个参数的方法
通知( Advice ) : 在切入点处执行的操作,也就是共性功能
通知类:定义通知的类
切面( Aspect ) : 描述通知与切入点的对应关系
1.2 AOP入门案例
导入Aspect坐标
1 2 3 4 5 <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.9.4</version > </dependency >
写一个通知类,写一个通知,一个切入点
设置切入点的注解,绑定通知与切入点
切入点定义依托一个不具有实际意义的方法进行,即无参数,无返回值, 方法体无实际逻辑 (如下的pc方法)
将通知类转为bean,使用@Aspect注解让spring将通知类以aop来处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Component @Aspect public class MyAdtive { @Pointcut("execution(void org.example.dao.BookDao.update())") private void pc () {} @Before("pc()") public void method () { System.out.println(System.currentTimeMillis()); } }
在配置类中打开aop注解开发模式@EnableAspectJAutoProxy
1 2 3 4 5 6 @Configuration @ComponentScan("org.example") @EnableAspectJAutoProxy public class SpringConfig {}
1.3 AOP工作流程
工作流程
Spring容器启动
读取所有切面配置中的切入点
初始化bean ,判定bean对应的类中的方法是否匹配到任意切入点
匹配失败 ,创建对象
匹配成功 ,创建原始对象(目标对象)的代理对象
获取bean执行方法
核心概念
目标对象( Target ) : 原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的
代理( Proxy) :目标对象无法直接完成工作,需要对其进行功能回填 ,通过原始对象的代理对象实现
1.4 AOP切入点表达式
语法格式
切入点:要进行增强的方法
切入点表达式:要进行增强的方法的描述方式
切入点表达式标准格式 :动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
动作关键字:描述切入点的行为动作, 例如execution表示执行到指定切入点
访问修饰符: public , private等,可以省略
返回值
包名
类/接口名.
方法名
参数
异常名:方法定义中抛出指定异常,可以省略
切入点表达式通配符:
* :单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
.. :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
+:专用于匹配子类类型
书写技巧
1.5 AOP通知类型
AOP通知描述了抽取的共性功能, 根据共性功能抽取的位置不同,最终运行代码时要将其加入到合理的位置
AOP通知共分为5种类型
前置通知
后置通知
环绕通知(重点)
返回后通知(了解)
抛出异常后通知 (了解)
前置通知@Before
1 2 3 4 @Before("pc()") public void before () { System.out.println("Before Adtive" ); }
后置通知@After
1 2 3 4 @After("pc()") public void after () { System.out.println("After Adtive" ); }
环绕通知@Around
无返回值:
1 2 3 4 5 6 7 @Around("pc()") public void around (ProceedingJoinPoint pjp) throws Throwable { System.out.println("Around Before Adtive" ); pjp.proceed(); System.out.println("Around After Adtive" ); }
有返回值:
1 2 3 4 5 6 7 8 @Around("pc2()") public Object around2 (ProceedingJoinPoint pjp) throws Throwable { System.out.println("Around Before Adtive" ); Object rej = pjp.proceed(); System.out.println("Around After Adtive" ); return rej; }
注意:
环绕通知必须依赖形参ProceedingJoinPoint才 能实现对原始方法的调用, 进而实现原始方法调用前后同时添加通知
通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
对原始方法的调用可以不接收返回值 ,通知方法设置成void即可,如果接收返回值,必须设定为Object类型
原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void ,也可以设置成Object
由于无法预知原始方法运行后是否会抛出异常 ,因此环绕通知方法必须抛出Throwable对象
获取原方法信息:
Signature对象(执行签名信息)中的方法获取
getDeclaringType,获取声明类型(接口名)
getName,获取原方法名称
getDeclaringType().getName() = getDeclaringTypeName(),获取类型名
1 2 3 4 5 Signature signature = pjp.getSignature();System.out.println(signature.getDeclaringType()); System.out.println(signature.getName()); System.out.println(signature.getDeclaringType().getName()); System.out.println(signature.getDeclaringTypeName());
返回后通知@AfterReturning
1 2 3 4 @AfterReturning("pc()") public void afterReturning () { System.out.println("afterReturning Adtive" ); }
抛出异常后通知@AfterThrowing
1 2 3 4 @AfterThrowing("pc()") public void afterThrowing () { System.out.println("afterThrowing Adtive" ); }
1.6 AOP通知获取数据
获取参数
获取返回值
获取异常
1.7 AOP总结
四、Spring事务 1.1 事务简介
事务作用:在数据层保障一系列的数据库操作同成功同失败
Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败