Spring基本知识总结

68 阅读7分钟
###一、spring简介
````
一个轻量级,开源,J2EE框架
核心部分:IOC:控制反转,把创建对象的过程交给Spring进行管理
        AOP:面向切面,对已有功能进行增强
````
###二、搭建Spring
````
1.创建一个普通Java工程或一个maven工程
    创建maven工程则再pom文件导入核心依赖:
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>
    若普通工程则下载jar包引入
2.创建spring配置文件,名字随意,一般为springbean.xml
<?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="userService" class="com.edu.service.UserService"/>
</beans>
3.测试是否能获取到bean对象
public class UserServiceTest {

    @Test
    public void testAdd(){
        //加载spring配置文件
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath:springbeans.xml");
        //获取配置bean对象
        UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);
        userService.add();
    }
}
````
###三、IOC概念和原理
````
1.什么是IOC
    控制反转,将对象的创建给交给Spring管理
    降低耦合度
2.IOC是一个慨念,具体实现DI依赖注入
    xml解析,工厂模式,反射
    1.先解析xml配置文件获取到配置的bean
    2.使用工厂模式这种设计模式
    3.通过反射创建对象
        Class clazz = Class.forName("");
        clazz.newInstance();
3.IOC容器,本质是一个对象工厂,具体实现接口有两个
    1.BeanFactory:Spring内部使用的接口
    2.ApplicationContext:BeanFactory接口的子接口,提供更强大功能,供开发人员使用
        区别:
            BeanFactory在加载配置文件的时候是不会创建对象,在获取对象时在创建
            ApplicationContext加载配置文件时,就会创建配置文件中配置的对象
    ApplicationContext有两个具体实现类:
        ClassPathXmlApplicationContext(""),获取类路径下的配置文件
        FileSystemXmlApplicationContext(""),获取磁盘中的配置文件
IOC操作之bean管理:
    bean管理分为:创建对象和注入属性
        创建对象,xml方式和注解方式
            xml方式在配置文件中添加bean标签并指定唯一标识符和类全路径名
            例:<bean id="user" class="com.edu.pojo.User"></bean>
        属性注入(DI依赖注入),依赖注入时IOC的具体实现方式
            1.set注入和有参构造器注入
            set注入步骤:
                1.Java类中创建好属性和属性的set方法
                2.spring配置文件中在bean标签里面使用子标签property完成
                    例:<bean id="user" class="com.edu.pojo.User">
                            <!--name 属性名,value属性值-->
                            <property name="" value=""/>
                        </bean>
            2.有参构造注入:
                1.Java类中添加类的有参构造函数,添加了有参构造函数就需要显示指明无参构造(因为写了有参构造,不会默认创建无参构造了)
                2.配置文件中配置,与set不同的是使用constructor-arg标签
                        <bean id="book" class="com.edu.pojo.Book">
                        <!--index值是参数下标,也可以使用name,name值就写属性名-->
                            <constructor-arg index="0" value="西游记"/>
                            <constructor-arg index="1" value="吴贯中"/>
                        </bean>
            3.P名称空间注入,简化了set方式注入,底层就是set注入
                1.在beans标签中加入名称空间
                2.bean标签中使用p:属性名=""的方式注入
                    例:<bean id="user2" class="com.edu.pojo.User" p:username="jerry" p:password="123456"/>
    注入属性值不同类型的书写方法:
        1.字面量
            null值:
                <property name="username">
                    <null/>
                </property>
            特殊符号:
                两种处理方式:1.将特殊符号转义,例如< 转义为&lt;
                <property name="bname" value="&lt;&lt;三国演义&gt;&gt;"/>
                2.使用<![CDATA[ content ]]>包裹
                例:<property name="bname">
                    <value>
                        <![[<<三国演义>>]]>
                    </value>
                   </property>
        2.外部bean注入,使用ref属性
            <!--外部bean注入-->
            <bean id="userDao" class="com.edu.dao.UserDao"/>
            <!--bean创建,就是创建对象-->
            <bean id="userService" class="com.edu.service.UserService">
                <property name="userDao" ref="userDao"/>
            </bean>
        3.内部bean注入和级联赋值(ref注入外部bean也是一种级联赋值):
            //内部bean注入
            <bean id="book2" class="com.edu.pojo.Book">
                <property name="bname">
                    <value><![CDATA[<<红楼梦>>]]></value>
                </property>
                <property name="bauthor" value="曹雪芹"/>
                <property name="user">
                    <bean id="user3" class="com.edu.pojo.User">
                        <property name="username" value="zzy"/>
                        <property name="password" value="123"/>
                        <property name="books">
                            <null/>
                        </property>
                    </bean>
                </property>
            </bean>
            <!--级联赋值 注意,还是要引入一个外部bean,我认为是没对象怎么赋值呢,否则爆错NullValueInNestdPathException-->
            <bean id="book3" class="com.edu.pojo.Book">
                <property name="bname" value="&lt;&lt;水浒传&gt;&gt;"/>
                <property name="bauthor" value="施耐庵"/>
                <property name="user" ref="user"/>
                <property name="user.username" value="zzy"/>
                <property name="user.password" value="123"/>
                <property name="user.books">
                    <null/>
                </property>
            </bean>
        4.集合类属性注入:
                <bean id="cd" class="com.edu.pojo.CollectionDI">
                    <!--数组注入-->
                    <property name="arr">
                        <array>
                            <value>java</value>
                            <value>Mysql</value>
                        </array>
                    </property>
                    <!--list集合注入-->
                    <property name="list">
                        <list>
                            <value>c</value>
                            <value>c++</value>
                        </list>
                    </property>
                    <!--map集合-->
                    <property name="map">
                        <map>
                            <entry key="1" value="python"/>
                            <entry key="2" value="c#"/>
                        </map>
                    </property>
                    <!--set集合-->
                    <property name="set">
                        <set>
                            <value>oracle</value>
                            <value>SqlServer</value>
                        </set>
                    </property>
                </bean>
        5.当集合内的泛型是类的时候,将<value>标签改为<ref>并将创建号的bean引入
               <bean id="cl" class="com.edu.pojo.CollectionDTUpgrade">
                   <property name="coursesList">
                       <list>
                           <ref bean="course1"/>
                           <ref bean="course2"/>
                       </list>
                   </property>
               </bean>
               <bean id="course1" class="com.edu.pojo.Course" p:name="java"/>
               <bean id="course2" class="com.edu.pojo.Course" p:name="mysql"/>
        6.集合还可以提供公共部分,供所有需要引用的地方使用
            1.引入util名称空间
            2.使用<util:集合类型 id="">标签创建好公共部分、
            3.在<property>中使用ref属性引入
                 <bean id="course3" class="com.edu.pojo.Course" p:name="oracle"/>
                 <bean id="course4" class="com.edu.pojo.Course" p:name="sqlServer"/>
                 <!--提取集合公共部分-->
                 <util:list id="commonList">
                     <ref bean="course3"/>
                     <ref bean="course4"/>
                 </util:list>
                 <bean id="cl2" class="com.edu.pojo.CollectionDTUpgrade">
                     <property name="coursesList" ref="commonList"/>
                 </bean>
Spring中的bean类型:
    1.普通bean:
        定义什么类型就返回什么类型
    2.工厂bean
        返回的类型和定义的类型不一定一样,实现:
            1.创建类去继承FactoryBean接口并实现方法,在实现方法中去指定返回对象
bean的作用域:
    bean实例的创建在默认情况下是单例的,也可以通过设置bean标签的scope属性设置为多例的
    1.singleton,默认值,单例
    2.prototype,多例
    3.request,将创建的对象放入到request域对象中
    5.session,将创建的对象放到session对象中
    singleton和prototype的区别:
        singleton在加载配置文件的时候就会创建对象,prototype不会,它会在使用的时候创建
bean的生命周期:
    1.调用构造器初始化
    2.设置属性
    3.调用后置处理器的before方法,创建类实现BeanPostProcessor
    4.调用初始化方法,需要配置init_method
    5.调用后置处理器的after方法
    6.使用
    7.销毁,destroy_method,需要手动调用close().
    实际测试发现会调用9次BeanPostProcessor的方法
spring中自动装配xml方式。(实际使用基本上都是注解方式)
    1.什么是自动装配?
        spring可以根据属性名或属性类型自动给属性值进行注入
    2.实现
        bean标签中存在一个autowire属性,属性值可以是byName,byType
        <bean id="emp" class="com.edu.autowire.Emp" autowire="byType"/>
        <bean id="dept" class="com.edu.autowire.Dept"/>
    details:
        根据byName属性名注入时,bean标签的id需要和属性名一致。
        根据byType属性类型注入时,bean对应的class只能有一个。
spring在XML文件中引入外部文件:
    1.引入context名称空间
    2.使用context:property-placeholder引入
    3.在bean配置文件中使用${}的方式使用外部文件中的值
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.mysql.Driver}"/>
        <property name="url" value="${jdbc.mysql.url}"/>
        <property name="username" value="${jdbc.mysql.username}"/>
        <property name="password" value="${jdbc.mysql.password}"/>
    </bean>
````
####spring中注解实现bean管理:
````
    1.为什么要使用注解?
        简化配置开发
    2.如何实现利用注解创建对象和属性注入
        1.引入spring-aop依赖
        2.在bean.xml中引入context名称空间
        3.使用<context:component-scan base-package=""/>配置包扫描,多个包使用逗号隔开,或直接指定公共上级包
            details:
                注解扫描可以配置具体扫描那些注解和不扫描那些注解
                例:
                //表示不使用默认扫描过滤器,只扫描配置的
                <context:component-scan base-package="com.edu.annotation" use-default-filters="false">
                    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
                </context:component-scan>
                //使用默认的扫描过滤器,但是不扫描配置的注解
                <context:component-scan base-package="com.edu.annotation">
                    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
                </context:component-scan>
                
        4.spring提供了4个创建bean的注解:
            @Component
            @Controller
            @Service
            @Repository
        4个注解的功能一样,可以用来区分不同业务层
        /**
         * 里面的value可以不写,默认为类名称首字母小写。
         * 这里换成其它的注解也一样。
         */
        @Controller(value = "userController") //<bean id="userController" class="....."/>
        public class UserController {
            public void login(){
                System.out.println("login............");
            }
        }
````
####spring中注解实现属性注入
````
4个注解:
    @AutoWire
        根据属性类型注入
        //在controller中调用service方法
        //不需要添加set方法:Field injection is not recommended(不被推荐的),因为当userService有多个实现类的时候就会出错
        //NoUniqueBeanDefinitionException报错没有唯一指定的bean
        @Autowired
        private UserService userService;
    @Qualifier
        根据属性名称注入,需要和@AutoWire配合使用
        @Autowired
        //这个value是bean的id值,在创建bean的时候可以指定,没指定默认类名首字母小写
        //可以解决上面没有唯一指定报错的问题,这里指定唯一实现类
        @Qualifier(value = "userServiceImpl")
        private UserService userService;
    @Resource
        可以根据属性类型或属性名称注入
        @Resource(name=""),没有指定name的时候就是根据类型,指定了就是根据名称
        @Resource(name="userServiceImpl2")
    @Value
        普通属性注入
        @Value("abc")
        private String name;
        前提:当引入了外部配置文件后可以,使用${}的方式注入,外部配置文件中的值
        例:@Value("${jdbc.mysql.Driver}")
            private String name;
````
####spring完全注解开发
````
    使用配置类代替配置文件,
    1.创建一个配置类,例如BeanConfig
    2.使用@Configuration注解标注在类,指定为一个配置类
    3.使用@ComponentScan开始注解包扫描
````
###四、Spring AOP
````
 1.什么是AOP?
    面向切面编程,对业务进行隔离,对现有功能进行增强
 2.代理模式:
    通过一个代理对象去调用目标对象中的方法,在调用之前,之后,都能对方法进行增强,提高了解耦性,将核心业务逻辑和非核心业务逻辑分开。
    静态代理:
        静态代理是一对一的,一个目标类有一个代理对象,在代理类中也要实现目标类中的方法并在实现方法中添加非核心业务逻辑。
        例:class A implements B{
              public void method1(){}
           }
           class Aproxy implements B{
             private A target;
             public Aproxy(A target){
                this.target = target;
             }
             public void method1(){
                //执行前可以操作
                target.method1();
                //执行后可以操作,并且如果异常了还可以处理异常的情况
             }
           }
    动态代理:
        分为JDK代理和cglib代理,区别:jdk代理需要被代理类实现了接口,cglib不用
````
####4.1sop术语:
````
1.连接点:
    类里面可以被增强的方法
2.切入点:
    实际被增强的方法
3.通知:
    实际增强的逻辑部分
    5种通知类型:
        1.前置通知
            @Before,在方法执行之前执行
        2.后置
            @AfterReturning,有异常不会执行,在方法return之后执行
        3.最终
            @After,在方法执行之后执行
        4.异常
            @AfterThrowing,在方法发生异常执行
        5.环绕
            @Around,在方法前后都执行
4.切面:
    将通知应用到切入点
切入点表达式:
    execution(访问修饰符 返回值类型 类全路径.方法名(参数列表))
    例:executioin(* com.edu.controller.UserController.*(..))
    返回值类型可省略
    *:代表所有
    ..:代表参数列表
5.如何使用:
注解方式
    1.在增强类上使用@Aspect注解标注
    2.在配置文件或配置类中配置包扫描,和开启aop注解
details:
    1.公共切入点的提取
        1.@PointCut注解,将execution表达式传入
        2.将@PointCut注解的方法用啊来替代之前写切入点表达式的地方
    2.多个增强类对统一方法增强的优先级设置
        1.使用@Order(1)注解,传入一个数值,值越小,优先级越高
XML方式:
    1.引入aop命名空间
    2.创建本类对象和增强类对象
    3.配置文件中配置
        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="p" expression="execution(* com.edu.aopXmlDemo.A.test(..))"/>
            <!--配置切面-->
            <aop:aspect ref="ap">
                <!--配置通知方式-->
                <aop:before method="before"  pointcut-ref="p"/>
            </aop:aspect>
        </aop:config>
````
###五、jdbcTemplate
````
spring对jdbc的封装
1.引入jdbc的依赖
    spring-jdbc
    spring-tx
    spring-orm
    包括数据库连接的jar
2.在bean中配置JDBCTemplate类
3.调用方法实现增删改查,在查询时返回对象为一个实体类的时候可以使用RowMapper接口的实现类BeanPropertyRowMapper
````
###六、事务的管理
````
1.事务的概念:
    事务是数据库操作的基本单元,一组操作要么都成功,要么都失败
2.事务的四个特性:ACID
    原子性:一组操作要么都成功,要么都失败
    一致性:操作前后的总量不变,例如转账,前后的总金额不改变
    隔离性:操作同一条记录时互不干扰
    持久性:最终结果是保存在数据库中的一条记录
3.编程式事务管理:
    在代码中写开启事务,提交,关闭,回滚等操作
  声明式事务管理:(实际开发中使用)
spring提供的声明式事务管理,底层原理是AOP实现
PlatformTransactionManager接口下的不同实现类对应不用ORM框架的事务管理
JDBCTemplate和mybatis都是DataSourceManager
xml和注解两种实现方式:
    1.xml:
        1.配置事务通知
            <tx:advice id="ta">
                <tx:attributes>
                    <!--一系列方法的规则-->
                    <tx:method name="insert*"/>
                </tx:attributes>
            </tx:advice>
        2.配置切入点和切面
            <aop:config>
                <aop:pointcut id="pt" expression="execution(* com.edu.transactionDemo.*(..))"/>
                <aop:advisor pointcut-ref="pt" advice-ref="ta" />
            </aop:config>
    2.注解:
        1.在配置文件中引入tx名称空间
        2.配置具体事务管理实现类bean
        3.开启事务注解扫描并指定事务管理实现类
            <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"/>
            </bean>
            <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
        4.在具体类上使用@Transactional注解,可以作用在类或方法上,作用在类则类中所有方法都开启事务,作用在方法就只是方法开启。
    3.全注解实现新增了@Bean注解类似bean标签
    4.
4.事务的传播(propagation)行为:
    一个事务方法中调用另外一个事务方法时,执行的过程。spring定义了7种,重点下面3种
    1.REQIURED
        加入当前事务中执行
    2.REQIURED_NEW
        在当前事务中新增一个内部事务去管理调用方法的事务
    3.SUPPORT
        如果当前方法没有事务,那么调用方法(调用方法有事务)也可以不执行事务
        当前方法有事务,调用方法也可以不执行事务
隔离级别:ioslation
    事务具有隔离特性,多个事务之间不应相互影响。
    如果没有隔离特性,将会出现3个读的问题:
        脏读:一个事务读取到另一个事务还未提交的数据
        不可重复读:一个事务读取到另一个事务已经提交修改的数据
        幻读:一个事务读取到另一个事务已经提交添加的数据
    事务的隔离级别有4种:
    read uncommit:都存在
    read commit:存在不可重复读,幻读
    repeatable read:存在幻读,这也是MySQL默认的隔离级别
    serializable:3个问题都解决
事务的其它参数:
    timeout:超时直接回滚,spring默认值-1,就是不超时,单位秒
    readOnly:只读,默认false设置为true后就不能增删改了。
    rollBackFor:针对那些异常回滚
    noRollBackFor:针对那些异常不回滚

````
###七、新功能
````
一、整合日志框架
spring5已经不支持log4j
1.引入jar
2.创建日志配置文件
二、@Nullable和函数式风格创建对象
1、@Nullable注解使用在方法上:方法返回值可以为空
作用在属性上,属性可以为空,
作用在形参上,形参可以为空值
2、使用GenericApplicationContext可以将new出来的对象放到IOC容器中
三、整合junit
junit4: 
    1.引入junit4的jar和一个hamcrest的jar
    2.使用@RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration("classpath:jdbcbeans.xml")
        public class JunitTest {}
junit5:
    @ExtendWith(SpringExtension.class)
    @ContextConfiguration("classpath:jdbcbeans.xml")
    public class JunitTest {}
    以上两个注解可以用一个代替
    @SpringJUnitConfig(locations = "classpath:jdbcbeans.xml")
````
###八、webFlux需要前置知识,springMVC,springboot,Java8新特性