美文网首页
[java]43、Spring-03

[java]43、Spring-03

作者: 史记_d5da | 来源:发表于2022-05-22 10:07 被阅读0次

    1、AOP

    1.1、AOPAspect Oriented Programming),面向切片编程

    Spring中使用AOP技术封装了动态代理功能
    1、在pom.xml中添加依赖库

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.9.6</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.6</version>
    </dependency>
    

    2、实现MethodBeforeAdvice接口,用来编写额外功能(会在目标方法执行之前执行)

    public class LogAdvice implements MethodBeforeAdvice {
        @Override
        public void before(Method method, Object[] objects, Object o) throws Throwable {
            System.out.println("LogAdvice --before --------------------" + method);
        }
    }
    

    3、在applicationContext.xml中配置aop

    <!--    附加代码-->
    <bean id="logAdvice" class="com.sj.aop.LogAdvice" />
    <aop:config>
    <!--        切入点,给哪些类的哪些方法增加附加代码-->
    <!--        execution(* *(..))代表所有类的所有方法都会被切入-->
        <aop:pointcut id="pc" expression="execution(* *(..))"/>
    <!--        附加代码-->
        <aop:advisor advice-ref="logAdvice" pointcut-ref="pc" />
    </aop:config>
    

    4、或者使用org.aopalliance.intercept.MethodInterceptor接口来编写额外功能

    public class LogInterceptor implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            System.out.println("1----------------------------");
            Object result = methodInvocation.proceed();
            System.out.println("2----------------------------");
            return result;
        }
    }
    
    <bean id="logInterceptor" class="com.sj.aop.LogInterceptor" />
    <aop:config>
    <!--        切入点,给哪些类的哪些方法增加附加代码-->
    <!--        execution(* *(..))代表所有类的所有方法都会被切入-->
        <aop:pointcut id="pc" expression="execution(* *(..))"/>
    <!--        附加代码-->
        <aop:advisor advice-ref="logInterceptor" pointcut-ref="pc" />
    </aop:config>
    
    1.2、AOP-动态代理底层实现

    1、Spring动态代理底层实现
    如果目标类有实现接口,使用JDK实现
    如果目标类没有实现接口,使用CGLib实现
    BeanPostProcessorpostProcessAfterInitialization方法中创建代理对象
    参照AbstractAutowireCapableBeanFactoryapplyBeanPostProcessorsAfterInitialization方法(源码如下)

    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
                throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }
    

    2、可以通过proxy-target-class属性修改底层实现方案
    true:强制使用CGLib
    false:按照默认做法
    <aop:config proxy-target-class="true">

    1.3、AOP-切入点表达式

    常见的切入点指示符(pointcut designators) 有
    executionargswithin@annotation、还可以使用&&and)、||or)、!组合切入点表达式
    1、execution
    任意公共方法:execution(public * *(..))
    名字以set开头的任意方法:execution(* set*(..))
    UserService接口定义的任意方法:execution(* com.sj.service.UserService.*(..))
    service包中定义的任意方法:execution(* com.sj.service.*.*(..))
    service包中定义的任意方法(包括子包):execution(* com.sj.service..*.*(..))
    包含2个String参数的任意方法:execution(* *(String, String))
    包含1个Serializable参数的任意方法:args(java.io.Serializable)
    service包中的任意方法:within(com.sj.service.*)
    service包中的任意方法(包括子包):within(com.sj.service..*)
    带有自定义注解(HeHe)的方法:@annotation(com.sj.aop.HeHe)

    2、默认情况下,目标方法相互调用时,总共只会被切入一次。解决方案:拿到代理对象去调用目标方法

    @Override
    public boolean login(String username, String password) {
        System.out.println("09--login");
        ctx.getBean("userService", UserService.class).register(username, password);
        return false;
    }
    

    3、配置多个pointcutadvisor

    <aop:config>
        <aop:pointcut id="pc" expression="within(com.sj.service.impl.PersonServiceImpl)"/>
        <aop:advisor advice-ref="logInterceptor" pointcut-ref="pc" />
        <aop:advisor advice-ref="logAdvice" pointcut-ref="pc" />
    </aop:config>
    

    2、事务管理

    2.1、声明式事务

    使用Spring的声明式事务,可以及其容易地进行事务管理
    只需要在XML中进行声明配置、一般在Service层进行事务管理

    <!--事务管理器-->
        <bean id="txMgr" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    <!--附加代码-->
        <tx:advice id="txAdvice" transaction-manager="txMgr">
            <tx:attributes>
                <tx:method name="list*"/>
                <tx:method name="save*"/>
                <tx:method name="update*"/>
                <tx:method name="test*"/>
            </tx:attributes>
        </tx:advice>
    <!--切面-->
        <aop:config>
            <aop:pointcut id="pc" expression="within(com.mj.service..*)"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pc" />
        </aop:config>
    
    2.2、propagation

    可以通过propagation属性设置事务的传播行为
    用于指定当事务嵌套时,如何管理事务,如下事务嵌套

    tx1-begin
        tx2-begin
        tx2-end
    
        tx3-begin
        tx3-end
    tx1-end
    

    Service调用Service时,会出现事务嵌套

    propagation
    <tx:method name="list*" propagation="SUPPORTS" />
    <tx:method name="save*" propagation="REQUIRED"/>
    <tx:method name="update*" propagation="REQUIRED"/>
    <tx:method name="test*" propagation="REQUIRED"/>
    
    2.3、read-only

    如果一个事务只执行读操作,那么数据库可能会采取某些优化措施
    read-only设置为true:告诉数据库这是个只读事务
    只适用于REQUIRED或者是REQUIRED_NEW

    <tx:method name="list*" propagation="REQUIRED" read-only="true"/>
    
    2.4、time-out

    单位是秒,默认是-1(默认情况处理),超时会抛出异常

    <tx:method name="list*" timeout="4"/>
    
    2.5、rollback-forno-rollback-for

    默认情况下,RuntimeExceptionError会导致事务回滚,而Exception不会
    rollback-for:设置哪些异常会导致事务回滚(在RuntimeExceptionError基础上增加一些异常)
    no-rollback-for
    rollback-for:设置哪些异常不会导致事务回滚(在Exception基础上增加一些异常)

    <tx:method name="save*" 
               rollback-for="java.io.IOException,InterruptedException"
               no-rollback-for="RuntimeException, Error"/>
    
    2.6、isolation

    事务的隔离级别
    如果多个事务同时操作一份数据,可能引发以下问题
    1、脏读:一个事务读取到了另一个事务没有提交的数据
    2、不可重复读:一个事务范围内两个相同的查询却返回了不同数据
    3、幻读:一个事务发现了之前本来确认不存在的数据
    可以设置隔离级别来解决上述问题(由上到下,性能依次降低)
    READ UNCOMMITTED:什么也解决不了
    READ COMMITED:可以防止脏读
    REPEATABLE READ:可以防止脏读,不可重复读(MySQL的默认级别)
    SERLALIZABLE:可以防止脏读,不可重复读,幻读(对整张表进行加锁)

    • 查询隔离级别的SQL语句
      SELECT @@TX_ISOLATION
    • 设置隔离级别
      SET GLOBAL TRANSACTION ISOLATION LEVEL隔离级别

    相关文章

      网友评论

          本文标题:[java]43、Spring-03

          本文链接:https://www.haomeiwen.com/subject/rwkburtx.html