Spring spring框架概述
spring是一个轻量级的开源框架
spring解决企业开发的复杂性
spring有两个核心部分IOC 和Aop
spring下载地址
spring基本5个jar包
使用步骤:
导入jar包
在src目录下创建spring使用的xml配置文件(spring config文件)
配置相关对象
启动程序
IOC容器 通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中
使用IOC的目的:为了降低耦合度
IOC底层原理 xml解析、工厂模式、反射
IOC接口(BeanFactory) IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
spring提供IOC容器实现的两种方式
1 2 3 4 5 ApplicationContext context = new ClassPathXmlApplicationContext ("配置文件名.xml" )User user = context.getBean("对象配置的id值" , User.class);
IOC操作Bean管理(基于xml) Bean管理 Bean管理指的是两个操作
1 2 3 4 5 6 7 8 9 <bean id ="user" class ="com.springDemo.User" > </bean > id属性:给对象取一个别名(唯一标识) class属性:类全路径(包全路径) name属性:与id属性效果一致,但是name中可以添加特殊符号
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 <bean id ="user" class ="com.springDemo.User" > <property name ="userName" value ="jjw" > </property > <property name ="address" > <null > </null > </property > </bean > <bean id ="user" class ="com.springDemo.User" > <constructor-arg name ="userName" value ="jjw" > </constructor-arg > </bean > <bean id ="user" class ="com.test.User" p:userName ="jjw" > </bean >
注入外部bean
1 2 3 4 5 6 7 8 9 <bean id ="user" class ="com.springDemo.User" > <property name ="userName" value ="jjw" > </property > <property name ="address" ref ="address" > </property > </bean > <bean id ="address" class ="com.springDemo.Address" > <property name ="add" value ="heibeishifandaxue" > </property > </bean >
级联赋值
1 2 3 4 5 6 7 8 9 <bean id ="emp" class ="com.Emp" > <property name ="name" value ="jjw" > </property > <property name ="dept" ref ="dept" > </property > <property name ="dept.name" value ="技术部" > </property > </bean > <bean id ="dept" class ="com.Dept" > <property name ="dname" value ="后勤部" > </property > </bean >
注入集合属性
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 38 39 40 41 <bean id ="user" class ="com.springDemo.User" > <property name ="courses" > <array > <value > 123</value > <value > 234</value > <value > 345</value > </array > </property > <property name ="list" > <list > <value > 123</value > <value > 234</value > <value > 345</value > </list > </property > <property name ="map" > <map > <entry key ="" value ="" > </entry > <entry key ="" value ="" > </entry > <entry key ="" value ="" > </entry > </map > </property > <property name ="set" > <set > <value > 123</value > <value > 234</value > <value > 345</value > </set > </property > </bean >
提取集合类型
1、添加util配置
2、提取集合,并注入
1 2 3 4 5 6 7 8 9 <util:list id ="users" > <value > 123</value > <value > 234</value > <value > 345</value > </util:list > <bean id ="user" class ="com.User" > <property name ="users" ref ="users" > </property > </bean >
spring有两种类型bean,一种普通bean,另一种工厂bean(FactoryBean)
1、普通bean:在配置文件中定义bean类型就是返回类型
2、工厂bean:在配置文件定义bean类型可以和返回类型不一样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import org.springframework.beans.factory.FactoryBean;public class MyBean implements FactoryBean <User> { @Override public User getObject () throws Exception { User user = new User (); user.setUserName("jjw" ); return user; } @Override public Class<?> getObjectType() { return null ; } @Override public boolean isSingleton () { return FactoryBean.super .isSingleton(); } }
1 2 <bean id ="mybean" class ="com.test.MyBean" > </bean >
Bean的作用域 作用域就是单实例、多实例、request、session
在spring里面,可以设置bean实例是单实例或者多实例
在spring里面,默认情况是单实例
单例:
当bean为单例模式时,加载spring配置文件时就会创建单例对象
1 <bean ... scope ="singleton" >
多例:
当bean为多例时,执行getBean方法时才创建对象
1 <bean ... scope ="prototype" >
Bean的生命周期 1、通过构造器创建bean实例(无参构造)
2、为bean的属性设置值和对其他bean的引用(调用set方法)
(可以添加后置处理器,添加后在第3步之前将bean实例传递给后置处理器的postProcessBeforeInitialization方法)
3、调用bean的初始化方法(需要自己配置)
(可以添加后置处理器,添加后在第3步之后将bean实例传递给后置处理器的postProcessAfterInitialization方法)
4、bean可以使用
5、当容器关闭时,调用bean的销毁方法(需要自己配置)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.test;public class Orders { private String oname; public Orders () { System.out.println("第一步,执行无参构造方法" ); } public void setOname (String oname) { this .oname = oname; System.out.println("第二步,调用set方法设置属性值" ); } public void init () { System.out.println("第三步,执行初始化方法" ); } public void destroy () { System.out.println("第五步,执行销毁方法" ); } }
1 2 3 <bean id ="orders" class ="com.test.Orders" init-method ="init" destroy-method ="destroy" > <property name ="oname" value ="jjw" > </property > </bean >
Bean自动装配 根据指定的装配规则(属性名称 或属性类型 ),spring自动将匹配的属性值进行注入
1 2 3 4 5 6 7 8 9 10 11 12 <bean id ="user" class ="com.test.User" autowire ="byName" > </bean > <bean id ="orders" class ="com.test.Orders" > </bean > <bean id ="user" class ="com.test.User" autowire ="byType" > </bean > <bean id ="orders" class ="com.test.Orders" > </bean >
引入外部属性文件 1、创建外部属性文件,properties格式的文件
1 2 3 4 5 6 <!--以阿里的德鲁伊数据库连接池配置为例--> 建议加上***.***否则容易命名冲突 prop.driverClass =com.mysql.jdbc.Driver prop.url =jdbc:mysql://localhost:3306/userDb prop.userName =root prop.password =root
2、添加context上下文配置
3、将外部properties文件引入到spring配置文件中
1 2 3 4 5 6 7 8 <context:property-placeholder location ="classpath:***.properties" /> <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" > <property name ="driverClassName" value ="${prop.driverClass}" > </property > <property name ="url" value ="${prop.url}" > </property > <property name ="username" value ="${prop.userName}" > </property > <property name ="password" value ="${prop.password}" > </property > </bean >
IOC操作Bean管理(基于注解)
@Component:普通的组件
@Service:用于业务逻辑层
@Controller:用于控制层
@Repository:用于dao层
功能是一样的,都可以用来创建bean实例
基于注解创建对象 1、引入spring.aop.x.x.x.RELEASE.jar
2、开启组件扫描,添加context上下文配置(多个包之间逗号隔开)
1 2 <context:component-scan base-package ="要扫描的包(包名),包名,..." > </context:component-scan >
3、创建类,添加注解
1 2 3 4 @Component(value = "user") public class User { ... }
开启包扫描的细节
自定义扫描的包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <context:component-scan base-package ="com" use-default-filters ="false" > <context:include-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan > <context:component-scan base-package ="com" > <context:exclude-filter type ="annotation" expression ="org.springframework.stereotype.Component" /> </context:component-scan >
基于注解实现属性注入 @AutoWired:根据属性类型自动注入
@Qualifier:根据属性名称自动注入
@Resource:根据类型或者名称自动注入
@Value:注入普通类型属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class User { @Autowired private Orders orders; } public class User { @Autowired @Qualifier(value = "orders"/*id值*/) private Orders orders; } public class User { @Resource private Orders orders; } public class User { @Value(value = "jjw") private String name; }
基于注解注入多例 1、在需要多例调用的类上加 @Scope(“prototype”)
2、在进行注入时不能直接使用 @Autowired ,最简单的方法是使用工厂方式注入
1 2 3 4 @Autowired private ObjectFactory<T> objectFactory;T t = objectFactory.getObject();
完全注解开发 1、创建配置类,替代xml配置文件
1 2 3 4 @Configuration @ComponentScan(basePackages = "com.test") public class SpringConfig {}
2、加载配置类,通过配置类获取bean
1 2 3 4 5 6 7 8 public class Test { public static void main (String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext (SpringConfig.class); Orders orders = context.getBean("orders" ,Orders.class); orders.setOname("jjw" ); } }
AOP
AOP概念 什么是Aop
AOP底层原理 AOP底层使用了动态代理的方式,增强类中某个方法的功能
有两种情况的动态代理
1、有接口的情况,使用JDK动态代理
创建接口实现类代理对象,增强类的方法
实现:
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 public class JDKProxy { public static void main (String[] args) { Class[] interfaces = {UserDao.class}; UserDaoImpl userDaoImpl = new UserDaoImpl (); UserDao userDao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler () { @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法之前执行...." +method.getName()); Object result = method.invoke(userDaoImpl,args); System.out.println("方法之后执行...." +method.getName()); return result; } }); } }
2、没有接口的情况,使用CGLIB动态代理
创建子类的代理对象,增强子类的方法
AOP术语 1、连接点
类里面哪些方法可以被增强,这些方法称为连接点
2、切入点
实际被真正增强的方法,称为切入点
3、通知
4、切面
把通知应用到切入点的过程,称为切面
AOP操作 参考:https://www.cnblogs.com/joy99/p/10941543.html
spring框架一般都是基于AspectJ 实现AOP操作 *AspectJ不是spring的组成部分,它是一个独立的AOP框架
引入AspectJ依赖
语法结构
注解方式 1、创建User类 ,在类中定义方法
2、创建UserProxy增强类
3、进行通知的配置
在spring配置文件中开启配置扫描
使用注解创建User 和UserProxy
在增强类上添加注解**@Aspect**
在spring配置文件中开启生成代理对象
4、配置不同类型的通知
在增强类里面,在作为通知方法上添加通知类型注解,使用切入点表达式配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?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" xmlns:aop ="http://www.springframework.org/schema/aop" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd" > <context:component-scan base-package ="com" > </context:component-scan > <aop:aspectj-autoproxy > </aop:aspectj-autoproxy > </beans >
1 2 3 4 5 6 @Component public class User { public void add () { System.out.println("add......" ); } }
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 @Component @Aspect public class UserProxy { @Before("execution(* com.test.User.add(..))") public void before () { System.out.println("before....." ); } @After("execution(* com.test.User.add(..))") public void after () { System.out.println("after....." ); } @AfterThrowing("execution(* com.test.User.add(..))") public void afterThrowing () { System.out.println("afterThrowing....." ); } @Around("execution(* com.test.User.add(..))") public void around (ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ System.out.println("around1....." ); proceedingJoinPoint.proceed(); System.out.println("around2....." ); } }
1 2 3 4 5 6 7 8 public class Test { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext ("bean.xml" ); User user = context.getBean("user" ,User.class); user.add(); } }
抽取相同的切入点
1 2 3 4 5 6 7 8 9 @Pointcut("execution(* com.test.User.add(..))") public void pointCut () {}@Before("pointCut()") public void before () { System.out.println("before....." ); }
有多个增强类,对同一个方法进行增强,可以设置增强类优先级,使其按顺序增强
1 2 3 4 @Component @Aspect @Order(3) public class UserProxy {
配置文件方式 1、创建两个类,增强类和被增强类,创建方法
2、在spring配置文件中创建两个类对象
3、在spring配置文件中配置切入点
JdbcTemplate JdbcTemplate是spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库进行操作
引入jar包
数据库连接池配置
配置JdbcTemplate对象,注入DataSource
在dao层的dao实现类中注入JdbcTemplate对象
JdbcTemplate操作数据库 添加 1、对应数据库表创建类
2、在dao进行数据库添加操作
1 2 3 4 5 6 7 8 public void add (Book book) { String sql = "insert into t_book value(?,?)" ; int update = jdbcTemplate.update(sql, book.getName() , book.getPrice()); }
修改 1 2 3 4 5 6 7 public void updateBook (Book book) { String sql = "update t_book set book_naem=?,book_price=?, where book_id=?" ; int update = jdbcTemplate.update(sql, book.getName() , book.getPrice() , book.getId()); }
删除 1 2 3 4 5 6 public void deleteBook (Book book) { String sql = "delete from t_book where user_id=?" ; int update = jdbcTemplate.update(sql, book.getId()); }
查询 返回有多少条记录
1 2 3 4 5 public Integer selectCount () { String sql = "select count(*) from t_book" ; Integer count = jdbcTemplate.queryForObject(sql,Integer.class); return count; }
返回一个对象
1 2 3 4 5 6 7 public Book selectById (String id) { String sql = "select * from t_book where user_id = ?" ; Book book = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper <Book>(Book.class),id); }
返回一个集合
1 2 3 4 5 6 7 8 public List<Book> findAllBook () { String sql = "select * from t_book" ; List<Book> bookList = jdbcTemplate.query(sql,new BeanPropertyRowMapper <Book>(Book.class)); return bookList; }xxxxxxxxxx8 1public List<Book> findAllBook () {2 String sql = "select * from t_book" ;3 4
批量操作 批量添加
1 2 3 4 5 public void batchAdd (List<Object[]> batchArgs) { String sql = "insert into t_book value(?,?)" ; int [] count = jdbcTemplate.batchUpdate(sql,batchArgs); }
批量修改
1 2 3 4 5 public void batchUpdate (List<Object[]> batchArgs) { String sql = "update t_book set book_naem=?,book_price=?, where book_id=?" ; int [] count = jdbcTemplate.batchUpdate(sql,batchArgs); }
批量删除
1 2 3 4 5 public void batchDelete (List<Object[]> batchArgs) { String sql = "delete from t_book where user_id=?" ; int [] count = jdbcTemplate.batchUpdate(sql,batchArgs); }
事务 事务概念
事务时数据库操作最基本单元,逻辑上一组操作,要么都成功,要么都失败
在spring中进行事务操作有两种方式
1、编程式事务管理
2、声明式事务管理(底层使用AOP原理)
四大特性
示例(银行转账为例)
步骤
1、在spring配置文件中配置事务管理器
2、在spring配置文件中引入名称空间tx
3、开启事务注解
4、在service层上添加事务注解(也可以添加到方法上面)
如果把注解添加到类上面,这个类里面所有的方法都添加事务
如果把这个注解添加到方法上面,就只给某一个方法添加事务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" > <property name ="driverClassName" value ="${prop.driverClass}" > </property > <property name ="url" value ="${prop.url}" > </property > <property name ="username" value ="${prop.userName}" > </property > <property name ="password" value ="${prop.password}" > </property > </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" > </property > </bean > <tx:annotation-driver transaction-manager ="transactionManager" > </tx:annotation-driver >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Repository public class UserDaoImpl { @Autowired private JdbcTemplate jdbcTemplate; public void reduceMoney () { String sql = "update t_bank set money = money-? where username=?" ; jdbcTemplate.update(sql,100 ,"jjw1" ); } public void addMoney () { String sql = "update t_bank set money = money+? where username=?" ; jdbcTemplate.update(sql,100 ,"jjw2" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 @Service @Transactional public class UserService { @Autowired private UserDao userDao; public void accountMoney () { userDao.reduceMoney(); userDao.addMoney; } }
声明式事务管理参数配置 @Transaction(参数)
propagation:事务的传播行为
多事务方法直接进行调用,这个过程中事务是如何进行管理的(一个有无事务的方法调用另外一个有无事务的方法,事务如何进行处理)
spring定义了七种事务传播行为
ioslation:事务隔离级别
多事务操作之间不会产生影响,不会产生脏读,不可重复读、虚读
timeout:超时时间
事务需要在一定的时间内进行提交,否则进行回滚
默认为-1(不超时),设置时间已秒为单位
readOnly:是否只读
rollbackFor:回滚
noRollbackFor:不回滚
完全注解方式 创建配置类,使用配置类替代xml配置文件
spring5框架新功能 整个spring5框架是基于Java8的 ,运行时兼容JDK9
支持整合日志框架 spring5框架自带了通用的日志封装,官方建议使用Log4j2
整合Log4j2
1、引入jar包
2、创建log4j2.xml(名称固定)配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?xml version="1.0" encoding="utf-8" ?> <configuration status ="INFO" > <appenders > <console name ="Console" target ="SYSTEM_OUT" > <PatternLayout pattern ="%d{yyyY-MM-dd HH:mm : ss .sss} [t] %-5level %logger{36} - %msg%n" /> </console > </appenders > <loggers > <root level ="info" > <appender-ref ref ="Console" /> </root > </loggers > </configuration >
3、自定义日志内容
1 2 3 4 5 private static final Logger log = LoggerFactory.getLogger(Test.class);public static void main (String[] args) { log.info("info............" ); }
Nullable注解和函数式注册对象 @Nullable
@Nullable注解可以使用在方法上面,属性上面,参数上面
方法:表示方法返回值可以为空,不会报空指针异常
属性值:表示属性值可以为空
参数:表示参数值可以为空
函数式注册对象
1 2 3 4 5 6 7 GenericApplicationContext context = new GenericApplicationContext ();context.refresh(); context.registerBean("user" ,User.class,()-> new User ()); User user = (User) context.getBean("user" );
单元测试框架(JUnit5) 整合JUnit4
1、引入依赖
2、创建测试类,使用注解方式完成
1 2 3 4 5 6 7 8 9 10 11 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:bean.xml") public class Jtest { @Autowired User user; @Test public void test () { user.add(); } }
若不使用JUnit4框架的话test方法中需要加载配置文件后才能使用ioc容器中的bean,使用了@RunWith注解将会自动开启ioc容器,不需要再通过getBean()方法获得bean
整合JUnit5
1、引入依赖
2、创建测试类,使用注解方式完成
1 2 3 4 5 6 7 8 9 10 11 12 13 @SpringJUnitConfig(locations = "classpath:bean.xml") public class Jtest { @Autowired User user; @Test public void test () { user.add(); } }