Spring(二:AOP)

AOP:Aspect Oriented Programming,面向切面编程,
把业务代码中公共的代码抽离出来。然后再通过动态代理的方式动态的切入到页面代码中。
就跟抽方法一个道理,抽公共的部分,但是并不在类中再调用,而是在事务管理器里面织入(规定通知的执行顺序)
使用:事务管理,日志管理,性能监测,权限校验;

===============================================================
AOP术语

连接点(Joinpoint):程序执行的某一个特定位置,如类初始前后,方法的运行前后。而Spring只支持方法的连接点。
切点(Pointcut):切点可以定位到相应的连接点,一个切点可以定位多个连接点。
增强(Advice):又被称为通知,完成逻辑的增强。
目标对象(Target):增强逻辑织入的目标类。
引介(Introduction):特殊的增强,为类添加一些属性和方法。
织入(Weaving): 将增强添加到目标类的具体连接点上的过程。Spring使用动态代理织入。
代理(Proxy):一个类(原类)被织入增强(逻辑)后,就产生一个结果类,称为代理类。
切面(Aspect):由切点和增强组成

===================================================================
自己完成动态代理是非常麻烦的,但Spring已经把动态代理部分完成,我们只需要做一些简单的配置(通过xml或者使用注解)就可以完成相应的功能。

配置三个要素:何时,何地,做什么事
何时:在目标对象的连接点的之前/之后/有异常…
何地:在哪些包中的哪些类的哪些方法上面执行(确定目标对象的连接点
做什么事: 在何时何地执行管理器中的哪个方法

==================================================================
导包:pom.xml中

		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.8</version>
        </dependency>

一、Xml版实现AOP
1、事务管理器

/**
 * 切面类。事务管理器
 */
public class TxManager {
    public void start() {
        System.out.println("开启事务");
    }

    public void commit() {
        System.out.println("提交事务");
    }

    public void rollback(Throwable throwable) {
        System.out.println("回滚事务,原因是:" + throwable.getMessage());
    }

    public void close() {
        System.out.println("关闭事务");
    }

	/**
	*	如果用>=2个通知,那么建议使用环绕通知,且不需要用另外几个通知,
	*	原因一:因为那几个通知的执行是没有顺序的,比如after和after-returning
	*	   二:因为会重复,它们同时存在的情况下,其他通知不会被取消         	
	*/
    public void around(ProceedingJoinPoint joinPoint) {
        try {
            start();
            //就是调用目标类的方法
            joinPoint.proceed();
            commit();
        } catch (Throwable e) {
            rollback(e);
        } finally {
            close();
        }
    }
}

2、配置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" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="txManager" class="cn.itsource._03_aop.TxManager"/>

    <bean id="userService" class="cn.itsource._03_aop.service.impl.UserServiceImpl"/>

    <bean id="deptService" class="cn.itsource._03_aop.service.impl.DeptServiceImpl"/>

    <!--aop:config:配置一个AOP-->
    <aop:config>
        <!--aop:pointcut配置一个切点
        expression:正则表达式,表示要在哪些类的哪些方法上加通知,就是何地
        第一个*:表示所有的返回值,
        第二个*:表示所有以I开头,以Service结束的类
        ..:表示任意的参数-->
        <aop:pointcut id="txPointCut"
                      expression="execution(* cn.itsource._03_aop.service.I*Service.save(..))"/>

        <!--aop:aspect:切面配置,
        ref:应用哪个bean作为切面类,就是事务管理器-->
        <aop:aspect ref="txManager">
            <!--before 前置通知,method表示调用切面类的方法-->
            <aop:before method="start" pointcut-ref="txPointCut"/>

            <!--after-returning后置通知-->
            <aop:after-returning method="commit" pointcut-ref="txPointCut"/>

            <!--after-throwing异常通知-->
            <aop:after-throwing method="rollback" pointcut-ref="txPointCut" throwing="throwable"/>
            
            <!--after 最终通知-->
            <aop:after method="close" pointcut-ref="txPointCut"/>
            
            <!--around 环绕通知-->
            <!--<aop:around method="around" pointcut-ref="txPointCut"/>-->
        </aop:aspect>
    </aop:config>
</beans>

================================================================
二、注解版实现AOP(推荐,因为不用繁琐的配置)
1、事务管理器

@Component
@Aspect //AOP的类注解,表示这个类是一个特殊的组件
public class TxManager {
	//设置切点
	@Pointcut("execution(* cn.itsource.aopanno.I*Service.*(..))")
	//是个空方法,给通知用
	public void pointcut(){}
	
	//前置通知
	@Before("pointcut()")
	public void begin(){
		System.out.println("开启事务....");
	}
	//后置通知
	@AfterReturning("pointcut()")
	public void commit(){
		System.out.println("提交事务...");
	}
	//异常通知
	@AfterThrowing(pointcut="pointcut()",throwing="e")
	public void rollback(Throwable e){
		System.out.println("回滚事务....");
		System.out.println(e.getMessage());
	}
	//最终通知
	@After("pointcut()")
	public void close(){
		System.out.println("关闭资源....");
	}
	
	//@Around("pointcut()")//同样的,建议使用
	public Object around(ProceedingJoinPoint joinPoint){
		Object object = null;
		try {
			begin();
			object = joinPoint.proceed(); //执行相应的代码
			commit();
		} catch (Throwable e) {
			rollback(e);
		}finally{
			close();
		}
		return object;
	}
}

2、配置文件

<!-- 组件搜索 -->
<context:component-scan base-package="cn.itsource" />
<!-- 支持aop注解 -->
<aop:aspectj-autoproxy />

测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class SpringTest {
    @Autowired
    //这里注入的一定是接口,在Spring实现动态代理中有解释
    private IUserService userService;
    @Autowired
    private IDeptService deptService;

    @Test
    public void test() {
        userService.save();
    }

    @Test
    public void test2() {
        deptService.save();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值