- spring对AOP的实现(只有配置式)
前置通知(MethodBeforeAdvice)
后置通知(AfterReturingAdvice)
环绕通知(MethodInteceptor)
异常通知(ThrowsAdvice)
首先要导入支持AOP的两个jar包
定义目标类
public class SomeServiceImpl implements IsomeService {
@Override
public void doSome() {
System.out.println("-----doSome方法执行!------"+1/0);
}
@Override
public String doOther() {
System.out.println("-----doOther方法执行!------");
return "xioabai";
}
}
主业务接口
public interface IsomeService {
//目标方法
public void doSome();
public String doOther();
}
定义切面类(通知类,这里以后置通知为例)
public class MyAfterReturingAdvice implements AfterReturningAdvice {
@Override
public void **afterReturning**(Object **returnValue**, Method method, Object[] args, Object target) throws Throwable {
if(returnValue!=null){
returnValue=returnValue.toString().toUpperCase();
}
System.out.println("-----后置通知-------"+returnValue);
}
}
在配置文件中注册目标类
<!--注册目标类 -->
<bean id="someServiceImpl" class="com.hxh.service.impl.SomeServiceImpl"></bean>
注册切面:后置通知
<bean id="myMethodBeforeAdvice" class="com.hxh.aspect.MyMethodBeforeAdvice"></bean>
<!--后置通知-->
<bean id="myAfterReturingAdvice" class="com.hxh.aspect.MyAfterReturingAdvice"></bean>
注册动态代理工厂ProxyFactoryBean(建立目标类和切面类的联系)
<bean id="proxyFactoryBean" class="**org.springframework.aop.framework.ProxyFactoryBean**">
<property name="**target**" ref="someServiceImpl"></property>
<property name="**interfaces**" value="com.hxh.service.IsomeService"></property>//可以不写
<property name="**interceptorNames**" value="myThrowsAdvice"></property>
</bean>
客户端访问动态代理对象
public class TestStar {
@Test
public void testSpring(){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
IsomeService proxy = ac.getBean("**proxyFactoryBean**", IsomeService.class);
proxy.doSome();
String s=proxy.doOther();
System.out.println(s);
}
}
- AspectJ对AOP的实现(既支持配置式开发也支持注解式开发,可以指定时间点、切入点)
前置通知
后置通知
环绕通知
异常通知
最终通知(无论程序是否执行该通知都会执行,同try-catch-finally中finally的功能,常用于关闭资源)
在实现的过程中用到切入点表达式在此简单介绍:
exection([modifiers-pattern]访问权限
ret-type-pattern 返回值类型
[declaring-type-pattern] 全限定性类名
name-pattern(param-pattern)
[throws-pattern] 抛出异常类型)
切入点表达式要匹配的对象就是目标方法的方法名。所以,execution表达式中明显就是方法的签名。注意,表达式中加[ ]的部分表示可省略部分,各部分间用空格分开。在其中可以使用以下符号:
:0至多个任意字符
…:用在方法参数中,表示任意多个参数;用在包名后,表示当前包及其子包路径
+:用在类名后,表示当前类及其子类;用在接口后,表示当前接口及其实现类
举例:
execution(public * (…))
指定切入点为:任意公共方法。
execution( set (…))
指定切入点为:任何一个以"set"开始的方法。
execution( com.xyz.service..(…))
指定切入点为:定义在service包里的任意类的任意方法。
execution( com.xyz.service….(…))
指定切入点为:定义在service包或者子包里的任意类的任意方法。"…“出现在类名中时, 后面必须跟”",表示包、子包下的所有类。
execution( .service..(…))
指定只有一级包下的serivce子包下所有类(接口)中的所有方法为切入点
execution( …service..*(…))
指定所有包下的serivce子包下所有类(接口)中的所有方法为切入点
注解式
1.导入相应的jar包,引入AOP约束
2.编写切面类MyAspect(用到@Aspect–类体上表明当前类是一个切面)
***@Aspect***
public class MyAspect {
//前置通知
***@Before("execution(* *..service.*.doSome(..))")***
public void before(){
System.out.println("-----前置通知-------");
}
//后置通知
**@AfterReturning(value="execution(* *..service.*.doOther(..))",*returning = "result"*)**
public void afterReturing(Object result){
if(result!=null){
result=result.toString().toUpperCase();
}
System.out.println("-----后置通知----"+result);
}
//环绕通知
***@Around("execution(* *..service.*.doOther(..))")***
public void aroud(ProceedingJoinPoint pjp){
try {
System.out.println("-----环绕通知--目标方法执行前---");
Object result = pjp.proceed();
System.out.println("-----环绕通知--目标方法执行后---"+result);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
//异常通知
**@AfterThrowing(value="execution(* *..service.*.doSome(..))",throwing ="ex")**
public void throwing(Exception ex){
System.out.println("----异常通知-------"+ex);
}
//最终通知
***@After("execution(* *..service.*.doSome(..))")***
public void after(){
System.out.println("-----最终通知------");
}
}```
3.配置文件中注册切面
<bean id="myAspect" class="com.hxh.aspect.MyAspect"></bean>
4.注册AOP自动代理
```
<aop:aspectj-autoproxy/>
```
5.测试类测试
public class TestStar {
@Test
public void testSpring(){
ApplicationContext ac = new ClassPathXmlApplicationContext(“spring.xml”);
IsomeService proxy = ac.getBean(“someServiceImpl”, IsomeService.class);
proxy.doSome();
String s=proxy.doOther();
System.out.println(s);
}
}
**配置式**
1.在配置文件中进行AOP配置
<aop:config>
<aop:aspect ref="切面类">
前置通知
<aop:before method="方法名" pointcut-ref=id>
<aop:pointcut id="唯一" expression="切入点表达式"
带返回值的加一个
returning="方法中的参数">
<bean id="someServiceImpl" class="com.hxh.service.impl.SomeServiceImpl"></bean>
<bean id="myAspect" class="com.hxh.aspect.MyAspect"></bean>
<!--注册AOP配置-->
<aop:config>
<aop:pointcut id="doSomePc" expression="execution(* *..service.*.doSome(..))"></aop:pointcut>
<aop:pointcut id="doOtherPc" expression="execution(* *..service.*.doOther(..))"></aop:pointcut>
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="before" pointcut-ref="doSomePc"></aop:before>
<!--后置通知-->
<aop:after-returning method="afterReturing" pointcut-ref="doOtherPc" returning="result"></aop:after-returning>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="doOtherPc"></aop:around>
<!--异常通知-->
<aop:after-throwing method="throwing" pointcut-ref="doSomePc" throwing="ex"></aop:after-throwing>
<!--最终通知-->
<aop:before method="after" pointcut-ref="doSomePc"></aop:before>
</aop:aspect>
</aop:config>
Spring、AspectJ和AOP的关系:
对于AOP这种编程思想,很多框架都进行了实现,Spring就是其中之一,可以完成面向切面编程。然而,AspectJ也实现了AOP的功能,且实现方式更为便捷,使用更为方便,而且还支持注解式开发。所以,spring又将AspectJ对于AOP的实现也引入到自己的框架中。
在Spring中使用AOP开发时,一般使用AspectJ的实现方式。