基于maven的spring知识点个人总结(均实践)

本文总结了Spring框架的知识,包括IOC反向代理、依赖注入DI的XML和注解方式、读取多个XML文件、AOP概念及应用、以及基于AOP的事务管理。详细讲解了bean的生命周期、作用域以及事务的四个等级和七种传播方式。内容实用,适合初学者学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

笔者自学的框架,知识点来自网上学习教程,方便实惠,推荐,特此声明。

spring
spring中的ioc反向代理
  1. ApplicationContext接口(推荐)

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从spring中获取对象
        StudentService studentService = (StudentService) context.getBean("studentService");
        studentService.study();
    
  2. BeanFactory

    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    reader.loadBeanDefinitions(new FileSystemResource("F:\\java\\ssm\\learnspring\\src\\main\\resources\\applicationContext.xml"));
    
    
  3. bean的三种实例方式
    3.1 第一种为默认方法,通过实现bean的接口实现类来实例化

    <bean id="studentService" class="com.java.service.impl.StudentServiceImpl"/>
    

    3.2 以实例工厂模式返回bean的实现类

    <bean id="myFactory" class="com.java.factory.MyBeanFactory"/>
    <bean id="studentService" factory-bean="myFactory" factory-method="createStudentService"/>
    

    3.3 以静态工厂返回bean的实现类

    <bean id="studentService" class="com.java.factory.MyBeanFactory" factory-method="createStudentService"/>
    
  4. bean的生命周期和作用域
    4.1 作用域:设定bean的scope属性,有以下几种

    • singleton: 单态模式。即在一个Spring ioc容器中,使用 singleton 定义的 Bean 是单例的,只有一个实例。默认为单例的。
    • prototype: 原型模式。即每次使用 getBean 方法获取的同一个bean的实例都是一个新的实例。
    • request:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例。
    • session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 实例。
    • application:在一个web应用中会产生一个bean实例,就相当于在一个ServletContext中只有该bean的实例。
    • websocket:在一个websocket中会产生一个bean实例。

    4.2 bean的初始化和销毁

    <bean id="studentService" init-method="init" destroy-method="destroy"  class="com.java.service.impl.StudentServiceImpl"/>
    

    4.3bean初始化的前后操作

    public class MyBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("执行before");
        //这里要将bean返回
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
        if ("studentService".equals(beanName)) {
            //创建InvocationHandler对象
            InvocationHandler invocationHandler = ((Object p, Method method, Object[] args) -> {
                //调用study方法时使用动态代理对其进行增强
                if ("study".equals(method.getName())) {
                    System.out.println("======目标方法开始=======");
                    //执行目标方法
                    Object result = method.invoke(bean, args);
                    System.out.println("======目标方法结束=======");
    
                    return result;
                }
    
                return method.invoke(bean, args);
            });
    
            //增强bean
            Object proxy = Proxy.newProxyInstance(
                    bean.getClass().getClassLoader(),
                    bean.getClass().getInterfaces(),
                    invocationHandler
            );
    
            System.out.println("postProcessAfterInitialization执行");
            return proxy;//把增强的代理类返回
        }
    
        return bean;
    }
    }
    
依赖注入DI
  1. xml(可通过autowire="byName"属性设置注入方式,黄体部分可修改)
    1.1 构造方式
    <bean id="userService" class="com.monkey1024.service.impl.UserServiceImpl">
    	<constructor-arg name="userDao" ref="userDaoId"/>
    </bean>
    <bean id="userDaoId" class="com.monkey1024.dao.impl.UserDaoImpl"/>
    
    1.2 setter方式
     <bean id="userService" class="com.monkey1024.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDaoId"/>
    </bean>
    <bean id="userDaoId" class="com.monkey1024.dao.impl.UserDaoImpl"/>
    
    1.3 注入集合
    <!-- Definition for javaCollection -->
       <bean id="javaCollection" class="com.tutorialspoint.JavaCollection">
    
          <!-- results in a setAddressList(java.util.List) call -->
          <property name="addressList">
             <list>
                <value>INDIA</value>
                <value>Pakistan</value>
                <value>USA</value>
                <value>USA</value>
             </list>
          </property>
    
          <!-- results in a setAddressSet(java.util.Set) call -->
          <property name="addressSet">
             <set>
                <value>INDIA</value>
                <value>Pakistan</value>
                <value>USA</value>
                <value>USA</value>
            </set>
          </property>
    
          <!-- results in a setAddressMap(java.util.Map) call -->
          <property name="addressMap">
             <map>
                <entry key="1" value="INDIA"/>
                <entry key="2" value="Pakistan"/>
                <entry key="3" value="USA"/>
                <entry key="4" value="USA"/>
             </map>
          </property>
    
          <!-- results in a setAddressProp(java.util.Properties) call -->
          <property name="addressProp">
             <props>
                <prop key="one">INDIA</prop>
                <prop key="two">Pakistan</prop>
                <prop key="three">USA</prop>
                <prop key="four">USA</prop>
             </props>
          </property>
    
       </bean>
    
    </beans>
    
  2. 注解
    扫描包:
    <!--文件扫描器-->
    <context:component-scan base-package="com.monkey1024"/>
    
    2.1注册bean
    @Component:
    @Repository 用于对 DAO 实现类进行注解
    @Service 用于对 Service 实现类进行注解
    @Controller 用于对 Controller 实现类进行注解
    2.2注入bean
    spring提供@Autowired注解(可用@Qualifier设置id)
    jdk提供@Resource注解,作用同上
    @Scope注解:指定bean的作用域
spring读取多个xml文件
  1. 方式一,在主程序中读取多个文件
    String[] files = {"spring-aop.xml","spring-bean.xml","applicationContext.xml"};
    ApplicationContext context = new ClassPathXmlApplicationContext(files);
    
  2. 方式二 将xml配置文件导入到主xml中
     <import resource="spring-aop.xml"/>
     <import resource="spring-bean.xml"/>
     <import resource="spring-*.xml"/>
     
    
AOP
  1. 术语介绍
    (1)目标对象(Target)
    目标对象指 将要被增强的对象。即包含主业务逻辑的类的对象。上例中的UserDaoImpl 的对象若被增强,则该类称为目标类,该类对象称为目标对象。当然,不被增强,也就无所谓目标不目标了。

    (2)切面(Aspect)
    切面泛指非业务逻辑。上例中的事务处理、日志处理就可以理解为切面。常用的切面有通知,实际就是对业务逻辑的一种增强。

    (3)连接点(JoinPoint)
    连接点指可以被切面织入的方法。通常业务接口中的方法均为连接点。

    (4)切入点(Pointcut)
    切入点指切面具体织入的方法。在 UserDaoImpl 类中,若 addUser()被增强,而doOther()不被增强,则 addUser()为切入点,而 doOther()仅为连接点。 被标记为 final 的方法是不能作为连接点与切入点的,因为是不能被修改的,不能被增强的。

    (5)通知(Advice)
    通知是切面的一种实现,可以完成简单织入功能(织入功能就是在这里完成的)。上例中的MyInvocationHandler 就可以理解为是一种通知。换个角度来说,通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。切入点定义切入的位置,通知定义切入的时间。Advice有下面几种,这里使用常用的AspectJ方式:

    • 前置通知(Before advice):在连接点之前执行,即目标方法执行之前执行。
    • 后置通知(After returning advice):在连接点正常结束之后执行,如果连接点抛出异常,则不执行。
    • 异常通知(After throwing advice):在连接点抛出异常后执行
    • 最终通知(After (finally) advice):在连接点结束之后执行,无论是否抛出异常,都会执行。
    • 环绕通知(Around advice):在连接点之前和之后均执行。

    (6)织入(Weaving)
    织入是指将切面代码插入到目标对象的过程。上例中 MyInvocationHandler 类中的 invoke()
    方法完成的工作,就可以称为织入。
    (7)aop代理(AOP proxy)
    spring中的aop代理有两种:jdk自带的动态代理和CGLIB代理。

  2. xml使用AOP
    添加依赖

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.13</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.0.4.RELEASE</version>
    </dependency>
    

    bean配置(笔者学习的举例)

    <!--注册bean-->
    <bean id="userService" class="com.monkey1024.service.impl.UserServiceImpl"/>
    <bean id="myAspect" class="com.monkey1024.aspect.MyAspect"/>
    <!--配置aop-->
    <aop:config>
        <!--定义切入点-->
        <aop:pointcut id="addUserPointcut" expression="execution(* com.monkey1024.service.impl.UserServiceImpl.addUser())"/>
        <aop:pointcut id="selectUserPointcut" expression="execution(* com.monkey1024.service.impl.UserServiceImpl.selectUser())"/>
        <aop:pointcut id="selectUserByIdPointcut" expression="execution(* com.monkey1024.service.impl.UserServiceImpl.selectUserById(..))"/>
        <aop:pointcut id="updateUserPointcut" expression="execution(* com.monkey1024.service.impl.UserServiceImpl.updateUser())"/>
        <aop:pointcut id="deleteUserPointcut" expression="execution(* com.monkey1024.service.impl.UserServiceImpl.deleteUser())"/>
    
        <!--定义切面-->
        <aop:aspect ref="myAspect">
            <!--前置通知-->
            <aop:before method="before" pointcut-ref="addUserPointcut"/>
            <!--后置通知-->
            <aop:after-returning method="afterReturning" pointcut-ref="updateUserPointcut" returning="result"/>
            <!--异常通知-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="selectUserByIdPointcut" throwing="e"/>
            <!--最终通知-->
            <aop:after method="after" pointcut-ref="selectUserPointcut"/>
            <!--环绕通知-->
            <aop:around method="around" pointcut-ref="deleteUserPointcut"/>
        </aop:aspect>
    </aop:config>
    
    

    bean配置(spring官网举例)

        <aop:config>
       <aop:aspect id="myAspect" ref="aBean">
          <aop:pointcut id="businessService"
             expression="execution(* com.xyz.myapp.service.*.*(..))"/>
          <!-- a before advice definition -->
          <aop:before pointcut-ref="businessService" 
             method="doRequiredTask"/>
          <!-- an after advice definition -->
          <aop:after pointcut-ref="businessService" 
             method="doRequiredTask"/>
          <!-- an after-returning advice definition -->
          <!--The doRequiredTask method must have parameter named retVal -->
          <aop:after-returning pointcut-ref="businessService"
             returning="retVal"
             method="doRequiredTask"/>
          <!-- an after-throwing advice definition -->
          <!--The doRequiredTask method must have parameter named ex -->
          <aop:after-throwing pointcut-ref="businessService"
             throwing="ex"
             method="doRequiredTask"/>
          <!-- an around advice definition -->
          <aop:around pointcut-ref="businessService" 
             method="doRequiredTask"/>
       ...
       </aop:aspect>
    </aop:config>
    <bean id="aBean" class="...">
    ...
    </bean>
    

    表达式

    execution ( 
    [modifiers-pattern]  访问权限类型
    ret-type-pattern  返回值类型
    [declaring-type-pattern]  全限定性类名
    name-pattern(param-pattern)  方法名(参数名)
    [throws-pattern]  抛出异常类型 
    )
    

    表达式举例

        execution(public * *(..)) 
    指定切入点为:任意公共方法。
    
    execution(* set*(..)) 
    指定切入点为:任何一个以“set”开始的方法。
    
    execution(* com.xyz.service.*.*(..)) 
    指定切入点为:定义在 service 包里的任意类的任意方法。
    
    execution(* com.xyz.service..*.*(..))
    指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“..”出现在类名中时,后面必须跟“*”,表示包、子包下的所有类。
    
    execution(* *.service.*.*(..))
    指定只有一级包下的 serivce 子包下所有类(接口)中所有方法为切入点 
    
    execution(* *..service.*.*(..))
    指定所有包下的 serivce 子包下所有类(接口)中所有方法为切入点 
    
    execution(* *.ISomeService.*(..))
    指定只有一级包下的 ISomeSerivce 接口中所有方法为切入点 
    
    execution(* *..ISomeService.*(..))
    指定所有包下的 ISomeSerivce 接口中所有方法为切入点 
    
    execution(* com.xyz.service.IAccountService.*(..)) 
    指定切入点为:  IAccountService  接口中的任意方法。 
    
    execution(* com.xyz.service.IAccountService+.*(..)) 
    指定切入点为:  IAccountService  若为接口,则为接口中的任意方法及其所有实现类中的任意方法;若为类,则为该类及其子类中的任意方法。 
    
    execution(* joke(String,int)))
    指定切入点为:所有的 joke(String,int)方法,且 joke()方法的第一个参数是 String,第二个参    数是 int。如果方法中的参数类型是 java.lang 包下的类,可以直接使用类名,否则必须使用全限定类名,如 joke( java.util.List, int)execution(* joke(String,*))) 
    指定切入点为:所有的 joke()方法,该方法第一个参数为 String,第二个参数可以是任意类型,如 joke(String s1,String s2)joke(String s1,double d2)都是,但 joke(String s1,double d2,String s3)不是。
    
    execution(* joke(String,..)))   
    指定切入点为:所有的 joke()方法,该方法第  一个参数为 String,后面可以有任意个参数且参数类型不限,如 joke(String s1)joke(String s1,String s2)joke(Strings1,double d2,String s3)都是。
    
    execution(* joke(Object))
    指定切入点为:所有的 joke()方法,方法拥有一个参数,且参数是 Object 类型。joke(Object ob)是,但,joke(String s)joke(User u)均不是。
    
    execution(* joke(Object+))) 
    指定切入点为:所有的 joke()方法,方法拥有一个参数,且参数是 Object 类型或该类的子类。不仅 joke(Object ob)是,joke(String s)joke(User u)也是。
    
  3. 注解
    3.1 添加依赖

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.0.4.RELEASE</version>
        </dependency>
    

    3.2注册切面类bean@Aspect @Component
    3.3添加注解扫描以及aop注册

    <context:component-scan base-package="com.monkey1024"/>
    <!--配置AspectJ自动代理-->
    <aop:aspectj-autoproxy/>
    

    3.4笔者学习举例

    @Aspect
    @Component
    public class MyAspect {
    
        @Before("execution(* *..UserServiceImpl.addUser())")
        public void before() {
            System.out.println("========前置通知========");
        }
    
        @After("execution(* *..UserServiceImpl.selectUser())")
        public void after() {
            System.out.println("========最终通知========:");
        }
    
        @AfterThrowing(value = "execution(* *..UserServiceImpl.selectUserById(..))" ,throwing = "e")
        public void afterThrowing(Exception e) {
            System.out.println("========异常通知========:" + e);
        }
    
        @AfterReturning(value = "execution(* *..UserServiceImpl.updateUser())",returning = "result")
        public void afterReturning(int result) {
            System.out.println("========后置通知========:" + result);
        }
    
        @Around(value = "execution(* *..UserServiceImpl.deleteUser())")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("========环绕通知:前========:");
            Object proceed = pjp.proceed();
            System.out.println("========环绕通知:后========:");
    
            return proceed;
        }
    }
    

    3.5 官网举例

    @Aspect
    public class Logging {
       /** Following is the definition for a pointcut to select
        *  all the methods available. So advice will be called
        *  for all the methods.
        */
       @Pointcut("execution(* com.tutorialspoint.*.*(..))")
       private void selectAll(){}
       /** 
        * This is the method which I would like to execute
        * before a selected method execution.
        */
       @Before("selectAll()")
       public void beforeAdvice(){
          System.out.println("Going to setup student profile.");
       }
       /** 
        * This is the method which I would like to execute
        * after a selected method execution.
        */
       @After("selectAll()")
       public void afterAdvice(){
          System.out.println("Student profile has been setup.");
       }
       /** 
        * This is the method which I would like to execute
        * when any method returns.
        */
       @AfterReturning(pointcut = "selectAll()", returning="retVal")
       public void afterReturningAdvice(Object retVal){
          System.out.println("Returning:" + retVal.toString() );
       }
       /**
        * This is the method which I would like to execute
        * if there is an exception raised by any method.
        */
       @AfterThrowing(pointcut = "selectAll()", throwing = "ex")
       public void AfterThrowingAdvice(IllegalArgumentException ex){
          System.out.println("There has been an exception: " + ex.toString());   
       }  
    }
    下面是 Student.java 文件的内容:
    
    package com.tutorialspoint;
    public class Student {
       private Integer age;
       private String name;
       public void setAge(Integer age) {
          this.age = age;
       }
       public Integer getAge() {
          System.out.println("Age : " + age );
          return age;
       }
       public void setName(String name) {
          this.name = name;
       }
       public String getName() {
          System.out.println("Name : " + name );
          return name;
       }
       public void printThrowException(){
          System.out.println("Exception raised");
          throw new IllegalArgumentException();
       }
    }
    
基于aop的事务管理
  1. 四个事务等级

    DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ;Oracle默认为 READ_COMMITTED。
    READ_UNCOMMITTED:读未提交。未解决任何问题。
    READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
    REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
    SERIALIZABLE:串行化。解决脏读、不可重复读,幻读的问题,效率低。
    
  2. 七种传播方式

    REQUIRED
    指定的方法必须在事务内执行。若当前存在事务,就加入到当前事务中;若当前没有事
    务,则创建一个新事务。这种传播行为是最常见的选择,也是 Spring 默认的事务传播行为。
    如该传播行为加在 doOther()方法上。若 doSome()方法在调用 doOther()方法时就是在事
    务内运行的,则 doOther()方法的执行也加入到该事务内执行。若 doSome()方法在调用
    doOther()方法时没有在事务内执行,则 doOther()方法会创建一个事务,并在其中执行。
    
    SUPPORTS
    指定的方法支持当前事务,但若当前没有事务,也可以以非事务方式执行。
    
    MANDATORY
    指定的方法必须在当前事务内执行,若当前没有事务,则直接抛出异常。
    
    REQUIRES_NEW
    总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事务执行完毕。
    
    NOT_SUPPORTED
    指定的方法不能在事务环境中执行,若当前存在事务,就将当前事务挂起。
    
    NEVER
    指定的方法不能在事务环境下执行,若当前存在事务,就直接抛出异常。
    
    NESTED
    指定的方法必须在事务内执行。若当前存在事务,则在嵌套事务内执行;若当前没有事务,则创建一个新事务。
    
  3. xml方式
    在spring-mybatis.xml文件中配置事务管理器

     <!-- 事务管理器 -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
    

    配置事务管理

     <!-- 通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 传播行为 -->
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="create*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
            <tx:method name="select*" propagation="SUPPORTS" read-only="true" />
            <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
        </tx:attributes>
    </tx:advice>
    

    配置要切入的service

        <!-- 切面 -->
    <aop:config>
        <!--切入点必须是在service层-->
        <aop:advisor advice-ref="txAdvice"
                     pointcut="execution(* com.monkey1024.service.*.*(..))" />
    </aop:config>
    </beans>
    
  4. 使用注解配置事务管理器

      <!-- 事务管理器 -->
    <bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- 数据源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
    
    <!--开启注解事务驱动-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    

    然后使用@Transactional 注解即可,该注解可以用于类上,也可以用于方法上,需要注意的是,@Transactional 若用在方法上,只能用于 public 方法上。对于其他非 public方法,如果加上了注解@Transactional,虽然 Spring 不会报错,但不会将指定事务织入到该方法中。因为 Spring 会忽略掉所有非 public 方法上的@Transaction 注解。

    @Transactional中的属性如下:
    propagation :用于设置事务传播属性。该属性类型为 Propagation 枚举,默认值为Propagation.REQUIRED。
    isolation : 用于设置事务的隔离级别。该属性类型为 Isolation 枚举,默认值为Isolation.DEFAULT。
    readOnly:用于设置该方法对数据库的操作是否是只读的。该属性为 boolean,默认值为 false。
    timeout:用于设置本操作与数据库连接的超时时限。单位为秒,类型为 int,默认值为-1,即没有时限。
    rollbackFor:指定需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
    rollbackForClassName: 指定需要回滚的异常类类名。类型为 String[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
    noRollbackFor:指定不需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
    noRollbackForClassName:指定不需要回滚的异常类类名。类型为 String[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值