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();     } }