spring-AOP的使用的两种方式

AOP的使用

通过动态代理,可以在指定位置执行对应流程。这样就可以将一些横向的功能抽离出来形成一个独立的模块,然后在指定位置插入这些功能。这样的思想,被称为面向切面编程,亦即AOP
先定义配置文件 application-context.xml, application-common.xml,application-aop.xml,
application-context.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<import resource="classpath:application-beans.xml"/>
	<import resource="classpath:application-common.xml"/>
	<import resource="classpath:application-aop.xml"/>	
</beans>

application-common.xml 见详情.

application-aop.xml 定义如下:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
						http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
						http://www.springframework.org/schema/tx 
						http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
						http://www.springframework.org/schema/aop 
						http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--两种方式公共的配置 -->
	<aop:aspectj-autoproxy proxy-target-class="true"/>
	<!-- 声明一个需要织入到虚拟切面的逻辑(切面) -->
	<!--一 基于配置的方法使用的配置 -->	
	<!-- <bean id="logAspect" class="com.gupaoedu.vip.aop.aspect.LogAspect"></bean>

	<aop:config>
		<aop:aspect ref="logAspect">
			<aop:pointcut expression="execution(* com.gupaoedu.vip.aop.service..*(..))" id="logPointcut"/>
			<aop:before method="before" pointcut-ref="logPointcut"/>
			<aop:after-returning method="afterReturn" returning="boolean"  pointcut-ref="logPointcut"/>
			<aop:after method="after" pointcut-ref="logPointcut"/>
			<aop:after-throwing method="afterThrow" pointcut-ref="logPointcut"/>
		</aop:aspect>
	</aop:config>  -->
	
	<!-- 具体的方法就是切点 -->
	<!-- 如何定义一个具体的方法 -->
	<!-- 权限修饰符(public/private/protected可省略) 返回值(Void/自定义类型,用*表示任意返回值类型,必填的) 属于哪个包哪个类(省略).方法名称(参数列表,必填) throws 异常类型(可省略) -->
	<!-- 参数列表的不同跟什么有关呢?
		 1、参数的个数
		 2、参数的顺序
		 3、参数的类型	 
		 跟参数的名字没有任何关系,形式参数
		 如果一个方法用final修饰了,就意味着这个方法不能被重写
		 也就意味着我们的子类不能对这个方法进行扩展
		 代理是是无法实现的
	 -->
	<!-- execution(public * com.gupaoedu.vip.aop.service..*.*(..))-->	
</beans>
1.定义一个service类,包含一系列的业务处理方法
package com.gupaoedu.vip.aop.service;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import com.gupaoedu.vip.model.Member;

@Service
public class MemberManagerService {
	private final static Logger LOG = Logger.getLogger(MemberManagerService.class);
	
	public Member add(Member member){
		LOG.info("增加用户");
		return new Member();
	}
		
	public boolean remove(long id) throws Exception{
		LOG.info("删除用户");
		throw new Exception("这是我们自己跑出来的异常");
	}
}
--------------------------------------------------------------------
2.测试类 MemberManagerServiceTest
package com.gupaoedu.vip.aop.test;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.gupaoedu.vip.aop.service.MemberManagerService;

@ContextConfiguration(locations={"classpath*:application-context.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class MemberManagerServiceTest {
	@Autowired MemberManagerService memberManagerService;	
	@Test
//	@Ignore
	public void testAdd(){
		memberManagerService.add(null);
	}		
	//做事务代理的时候
	//TracationManage来管理事务操作(切面)
	//DataSource ,SessionFactory(DataSource)
    //DataSource 包含了连接信息,事物的提交或者回滚一些基础功能
	//通过连接点是可以获取到方法(切点)具体操作哪个DataSource
	//通过切面通知类型,去执行DataSource的功能方法	
	//完全裸露,一丝不挂
//	@Test
//	@Ignore
	public void testRemove(){
		try {
			memberManagerService.remove(0);
		} catch (Exception e) {
//			e.printStackTrace();
		}
	}	
}

一 基于配置

定义一个aspect类 里面定义了包含不同通知的时机和内容的通知方法

package com.gupaoedu.vip.aop.aspect;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
public class LogAspect {
	private final static Logger LOG = Logger.getLogger(LogAspect.class);
	
	public void before(JoinPoint joinPoint){
		LOG.info("调用方法之前执行" + joinPoint);
	}	
	public void after(JoinPoint joinPoint){
		LOG.info("调用之后执行" + joinPoint);
	}	
	public void afterReturn(JoinPoint joinPoint){
		LOG.info("调用获得返回值之后执行" + joinPoint);
//		return true;
	}	
	public void afterThrow(JoinPoint joinPoint){
		LOG.info("抛出异常之后执行" + joinPoint);
	}
}

二 基于注解

定义切面类 AnnotationAspect @Pointcut注解定义一个切点, @Before,@After,@AfterReturning,@AfterThrowing定义通知
将切点传入通知注解就能将切点和通知结合起来,并通过joinPoint能获取切点指代的业务方法的信息

package com.gupaoedu.vip.aop.aspect;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component//声明这个类是被SpringIOC容器来管理的,如果不声明,就无法做到自动织入
@Aspect//这个类被声明为是一个需要动态织入到我们的虚拟切面中的类
public class AnnotationAspect {
	private final static Logger LOG = Logger.getLogger(AnnotationAspect.class);
	//声明切点
	//因为要利用反射机制去读取这个切面中的所有的注解信息
	@Pointcut("execution(* com.gupaoedu.vip.aop.service..*(..))")
	public void pointcutConfig(){}
	
	@Before("pointcutConfig()")
	public void before(JoinPoint joinPoint){
		LOG.info("调用方法之前执行" + joinPoint);
	}
	
	@After("pointcutConfig()")
	public void after(JoinPoint joinPoint){
		LOG.info("调用之后执行" + joinPoint);
	}
	
	@AfterReturning(returning="returnValue",value="pointcutConfig()")
	public void afterReturn(JoinPoint joinPoint,Object returnValue){
		LOG.info("调用获得返回值" + returnValue);
	}
	
	@AfterThrowing("pointcutConfig()")
	public void afterThrow(JoinPoint joinPoint){
		System.out.println("切点的参数" + Arrays.toString(joinPoint.getArgs()));
		System.out.println("切点的方法" + joinPoint.getKind());
		System.out.println(joinPoint.getSignature());
		System.out.println(joinPoint.getTarget()); //生成以后的代理对象
		System.out.println(joinPoint.getThis());//当前类的本身(通过反射机制去掉用)		
		LOG.info("抛出异常之后执行" + joinPoint);
	}
}

切入点表达式的用法

切入点表达式 @Pointcut(“execution(* com.cjm.model….(…))”)
1、切入点表达式的格式:execution([可见性] 返回类型 [声明类型].方法名(参数) [异常])
2、切入点表达式通配符:
:匹配所有字符
…:一般用于匹配多个包,多个参数
+:表示类及其子类
3、切入点表达式支持逻辑运算符:&&、||、!
4、切入点表达式关键词:
1)execution:用于匹配子表达式。
//匹配com.cjm.model包及其子包中所有类中的所有方法,返回类型任意,方法参数任意
@Pointcut("execution(
com.cjm.model….(…))")
public void before(){}
2)within:用于匹配连接点所在的Java类或者包。
//匹配Person类中的所有方法
@Pointcut(“within(com.cjm.model.Person)”)
public void before(){}
//匹配com.cjm包及其子包中所有类中的所有方法
@Pointcut(“within(com.cjm…*)”)
public void before(){}
3) this:用于向通知方法中传入代理对象的引用。
@Before(“before() && this(proxy)”)
public void beforeAdvide(JoinPoint point, Object proxy){
//处理逻辑
}
4)target:用于向通知方法中传入目标对象的引用。
@Before(“before() && target(target)
public void beforeAdvide(JoinPoint point, Object proxy){
//处理逻辑
}
5)args:用于将参数传入到通知方法中。
@Before(“before() && args(age,username)”)
public void beforeAdvide(JoinPoint point, int age, String username){
//处理逻辑
}
6)@within:用于匹配在类一级使用了参数确定的注解的类,其所有方法都将被匹配。
@Pointcut(”@within(com.cjm.annotation.AdviceAnnotation)")
//所有被@AdviceAnnotation标注的类都将匹配
public void before(){}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Inherited
public @interface AdviceAnnotation {

}
7)@target:和@within的功能类似,但必须要指定注解接口的保留策略为RUNTIME。
@Pointcut("@target(com.cjm.annotation.AdviceAnnotation)")
public void before(){}
8)@args:传入连接点的对象对应的Java类必须被@args指定的Annotation注解标注。
@Before("@args(com.cjm.annotation.AdviceAnnotation)")
public void beforeAdvide(JoinPoint point){
//处理逻辑
}
public class Person {
public void say(Address address){
//处理逻辑
}
}
@AdviceAnnotation
public class Address {
}
如果需要在Person类的say方法被调用时触发beforeAdvide通知,那么say方法的参数对应的Java类型Address类必须要被@AdviceAnnotation标注。
9)@annotation:匹配连接点被它参数指定的Annotation注解的方法。也就是说,所有被指定注解标注的方法都将匹配。
@Pointcut("@annotation(com.cjm.annotation.AdviceAnnotation)")
public void before(){}
public class Person {
@AdviceAnnotation
public void say(Address address){
//处理逻辑
}
}
Person类的say方法被@AdviceAnnotation标注,所以它匹配。
10)bean:通过受管Bean的名字来限定连接点所在的Bean。该关键词是Spring2.5新增的。
@Pointcut(“bean(person)”)
public void before(){}
id为person的受管Bean中的所有方法都将匹配。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值