飞道的博客

AOP

227人阅读  评论(0)

AOP

AOP相关术语

Joinpoint(连接点):

所谓连接点是指那些被拦截到的点,在Spring中,这些点指的是方法,因为Spring只支持方法类型的连接点。

Pointtout(切入点):

所谓切入点是指我们要对那哪些Jointpoint进行拦截的定义。

Advice(通知/增强):

所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。

通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

Introduction(引介):

引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field.

Target(目标对象):

代理的目标对象。

Weaving(织入):

是指把增强应用到目标对象来创建新的代理对象的过程。

Spring采用动态代理织入,而Aspect采用编译期织入和类装载期织入。

Proxy(代理):

一个类被AOP织入增强后,就产生一个结果代理类。

Aspect(切面):

是切入点和通知(引介)的结合。

自定义的日志类

类中的方法也就是需要在增强方法中切入的方法

public class Logger{
    public void beforePrintLog(){
        System.out.println("前置通知方法执行");
	}
    public void afterReturningPrintLog(){
        System.out.println("后置通知方法执行");
	}
    public void afterThrowingPrintLog(){
        System.out.println("异常通知方法执行");
	}
    public void afterPrintLog(){
        System.out.println("最终通知方法执行");
	}
}

AOP在xml中配置:

需要导入依赖

<dependency>
	<groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.7</version>
</dependency>

该依赖是用来支持切入点表达式

例:execution(* com.muzi.service.impl..(…))

aop名称空间:

<beans xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="                      http://www.springframework.org/schema/aop   http://springframework.org/schema/ao/spring-aop.xsd">
</beans>
<!--配置spring的IOC,把service对象配置进来-->
<bean id="accountService" class="com.muzi.service.impl.AccountServiceImpl"></bean>
<!--配置Logger自定义日志类-->
<bean id="logger" class="com.muzi.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
	<!--配置切面-->
    <aop:aspect id="logAdvice" ref="logger">
    	<!--配置前置通知:在切入点方法执行之前执行-->
        <aop:before method="beforeprintLog" pointcut="execution(* com.muzi.service.impl.*.*(..))"></aop:before>
        <!--配置后置通知:在切入点方法正常执行之后执行,它和异常通知永远只能执行一个-->
        <aop:after-returning method="afterReturningPrintLog" pointcut="execution(* com.muzi.service.impl.*.*(..))"></aop:after-returning>
        <!--配置异常通知:在切入点方法执行产生异常之后执行,它和后置通知永远只能执行一个-->
        <aop:after-throwing method="afterThrowingPrintLog" pointcut="execution(* com.muzi.service.impl.*.*(..))"></aop:after-throwing>
        <!--配置最终通知:无论切入点方法是否正常执行它都会在其后面执行-->
        <aop:after method="afterPrintLog" pointcut="execution(* com.muzi.service.impl.*.*(..))"></aop:after>
    </aop:aspect>
</aop:config>

还可以进一步省略每个切入点的pointcut属性:

<!--配置spring的IOC,把service对象配置进来-->
<bean id="accountService" class="com.muzi.service.impl.AccountServiceImpl"></bean>
<!--配置Logger自定义日志类-->
<bean id="logger" class="com.muzi.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
	<!--配置切面-->
    <aop:aspect id="logAdvice" ref="logger">
    	<!--配置前置通知:在切入点方法执行之前执行-->
        <aop:before method="beforeprintLog" pointcut-ref="pt1"></aop:before>
        <!--配置后置通知:在切入点方法正常执行之后执行,它和异常通知永远只能执行一个-->
        <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>
        <!--配置异常通知:在切入点方法执行产生异常之后执行,它和后置通知永远只能执行一个-->
        <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>
        <!--配置最终通知:无论切入点方法是否正常执行它都会在其后面执行-->
        <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>
        <!--配置切入点表达式,id属性用于指定表达式的唯一标识,expression属性用于指定表达式内容。此标签写在aop:aspect标签内部只能当前切面使用。它还可以写在aop:aspect外面,此时变成了所有切面可用-->
        <aop:pointcut id="pt1" expression="excution(* com.muzi.service.impl.*.*(..))"></aop:pointcut>
    </aop:aspect>
</aop:config>

或者把aop:pointcut写在所有切面之前,被所有切面所共享:

<!--配置spring的IOC,把service对象配置进来-->
<bean id="accountService" class="com.muzi.service.impl.AccountServiceImpl"></bean>
<!--配置Logger自定义日志类-->
<bean id="logger" class="com.muzi.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
    <!--它还可以写在aop:aspect外面,此时变成了所有切面可用-->
    <aop:pointcut id="pt1" expression="excution(* com.muzi.service.impl.*.*(..))"></aop:pointcut>
	<!--配置切面-->
    <aop:aspect id="logAdvice" ref="logger">
    	<!--配置前置通知:在切入点方法执行之前执行-->
        <aop:before method="beforeprintLog" pointcut-ref="pt1"></aop:before>
        <!--配置后置通知:在切入点方法正常执行之后执行,它和异常通知永远只能执行一个-->
        <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>
        <!--配置异常通知:在切入点方法执行产生异常之后执行,它和后置通知永远只能执行一个-->
        <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>
        <!--配置最终通知:无论切入点方法是否正常执行它都会在其后面执行-->
        <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>
    </aop:aspect>
</aop:config>

配置环绕通知:

需要提前在自定义日志类中添加该方法:

public Object aroundPrintLog(ProceedingJoinPoint pjp){
        Object rtValue=null;
        try{
            //得到方法执行所需要的参数
            Object[] args=pjp.getArgs();
            System.out.println("Logger类中的aroundPointLog方法开始记录日志了。。。前置");
            //明确调用业务层方法(切入点方法)
            rtValue=pjp.proceed(args);
            System.out.println("Logger类中的aroundPointLog方法开始记录日志了。。。后置");
            return rtValue;   
        }catch(Throwable t){
            System.out.println("Logger类中的aroundPointLog方法开始记录日志了。。。异常");
        }finally{
            System.out.println("Logger类中的aroundPointLog方法开始记录日志了。。。最终");
        }
    }
<!--配置spring的IOC,把service对象配置进来-->
<bean id="accountService" class="com.muzi.service.impl.AccountServiceImpl"></bean>
<!--配置Logger自定义日志类-->
<bean id="logger" class="com.muzi.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
    <!--它还可以写在aop:aspect外面,此时变成了所有切面可用-->
    <aop:pointcut id="pt1" expression="excution(* com.muzi.service.impl.*.*(..))"></aop:pointcut>
	<!--配置切面-->
    <aop:aspect id="logAdvice" ref="logger">
        <!--配置环绕通知: 
        <aop:around method="aroundPointLog" pointcut-ref="pt1"></aop:around>
    </aop:aspect>
</aop:config>

Spring基于AOP的自定义事务控制

1.在xml中配置自定义事务控制

提前写自定义的事务类:

public class TransactionManager{
    @Autowired
    private ConnectionUtils connectionUtils;
    public void beginTransaction(){
        try{
            connectionUtils.getThreadConnectio().setAutoCommit(false);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    public void commit(){
        try{
            connectionUtils.getThreadConnction().commit();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    publc void rollback(){
        try{
            connectionUtils.getThreadConnection().rollback();
        }catch(Excepton e){
            e.printStackTrace();
        }
    }
    public void release(){
        try{
            connectionUtils.getThreadConnection().close();
            conectionUtils.removeConnection();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
}
<!--配置spring的IOC,把service对象配置进来-->
<bean id="accountService" class="com.muzi.service.impl.AccountServiceImpl"></bean>
<!--配置自定义事务管理器类-->
<bean id="txManager" class="com.muzi.utils.TransactionManager"></bean>
<!--配置AOP-->
<aop:config>
    <!--配置通用的切入点表达式-->
    <aop:pointcut id="pt1" expression="excution(* com.muzi.service.impl.*.*(..))"></aop:pointcut>
	<!--配置切面-->
    <aop:aspect id="logAdvice" ref="logger">
    	<!--配置前置通知:开启事务-->
        <aop:before method="beginTransaction" pointcut-ref="pt1"></aop:before>
        <!--配置后置通知:提交事务-->
        <aop:after-returning method="commit" pointcut-ref="pt1"></aop:after-returning>
        <!--配置异常通知:回滚事务-->
        <aop:after-throwing method="rollback" pointcut-ref="pt1"></aop:after-throwing>
        <!--配置最终通知:释放连接-->
        <aop:after method="release" pointcut-ref="pt1"></aop:after>
    </aop:aspect>
</aop:config>

2.使用AOP注解的自定义事务控制

推荐使用环绕通知!!!

@Conponent("txManager")
@Aspect
public class TransactionManager{
    @Autowired
    private ConnectionUtils connectionUtils;
    @Pointcut("execution(* com.muzi.service.impl.*.*(..))")
    private void pt1(){}
    @Before("pt1()")
    public void beginTransaction(){
        try{
            connectionUtils.getThreadConnectio().setAutoCommit(false);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    @AfterReturning("pt1()")
    public void commit(){
        try{
            connectionUtils.getThreadConnction().commit();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    @AfterThrowing("pt1()")
    publc void rollback(){
        try{
            connectionUtils.getThreadConnection().rollback();
        }catch(Excepton e){
            e.printStackTrace();
        }
    }
    @After("pt1()")
    public void release(){
        try{
            connectionUtils.getThreadConnection().close();
            conectionUtils.removeConnection();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    @Arround("pt1()")
    public Object arroundAdvice(ProceedingJoinPoint pjp){
        try{
            Object[] args=pjp.getArgs();
            this.beginTransaction();
            rtValue=pjp.proceed(args);
            this.commit();
            return rtValue;
        }catch(Throwable e){
            this.rollback;
            throw new RuntimeExcetion(e);
        }finally{
            this.release();
        }
    }
        
    }
}

Spring中基于XML的声明式事务控制配置

spring中基于XML的声明式事务配置步骤
1、配置事务管理器
2、配置事务的通知
此时我们徐亚导入事务的约束 tx名称空间和约束,同时也需要aop的 使用tx:advice标签配置事务通知
属性:
id:给事务通知起一个唯一标识
transaction-manager:给事务通知提供一个事务管理器引用
3、配置AOP中的通用切入点表达式
4、建立事务通知和切入点表达式的对应关系
5、配置事务的属性
是在事务的通知tx:advice标签的内部

<!--spring中基于XML的声明式事务配置步骤
	1、配置事务管理器
	2、配置事务的通知
			此时我们徐亚导入事务的约束  tx名称空间和约束,同时也需要aop的   使用tx:advice标签配置事务通知
属性:
id:给事务通知起一个唯一标识
transaction-manager:给事务通知提供一个事务管理器引用
	3、配置AOP中的通用切入点表达式
	4、建立事务通知和切入点表达式的对应关系
	5、配置事务的属性
			是在事务的通知tx:advice标签的内部
-->
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManagr">
	<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<!--配置事务的属性
		isolation:用于指定事务的隔离级别。
		no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚,没有默认值,表示任何事务都回滚。
		propagation:用于指定事务的传播行为,默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以用SUPPORTS。
		read-only:用于指定事务是否只读,只有查询方法才能设置为true,默认值是false,表示读写。
		rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他事务时,事务不回滚,没有默认值,表示任何事务都回滚。
		timeout:用于指定事务的超时时间,默认值是-1,表示永不超时,如果指定了数值,以秒为单位。
-->
    <tx:attributes>
    	<tx:method name="*" propagation="REQUIRED" read-only="false"/>
        <tx:method name="find" propagation="SUPPORTS" read-only="true"></tx:method>
    </tx:attributes>
</tx:advice>
<!--配置aop-->
<aop:config>
	<!--配置切入点表达式-->
    <aop:pointcut id="pt1" expression="excution(* com.mzi.service.impl.*.*(..))"></aop:pointcut>
    <!--建立切入点表达式和事务通知的对应关系-->
    <aop:advisor advice-ref="txAdvice" point-ref="pt1"></aop:advisor>
</aop:config>

Spring中基于注解的声明式事务控制配置

spring中基于注解的声明式事务配置步骤

1、开启事务管理器

2、开启Spring对事务注解的支持

在主配置类上加@EnableTransactionManagement或者在xml中配置:

<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

3、在需要事务支持的地方使用@Transactional注解

@Transactional
public class AccountServiceImp implements IAccountService{
    
}

转载:https://blog.csdn.net/l13kddd/article/details/105237056
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场