美文网首页
[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