您的位置:首页 > 编程语言 > Java开发

Spring入门之AOP

2017-04-26 15:04 274 查看
AOP 即 Aspect Oriental Program 面向切面编程 。首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务 所谓的周边功能,比如性能统计,日志,事务管理等等 。周边功能在Spring的变相切面编程AOP思想里,即被定义为切面 ,在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能
"编织" 在一起,这就叫AOP。

先看示例,我们有一个类叫AspectBiz类,这个类里的方法是核心的业务功能方法,例如此时有一个核心的业务功能方法biz()。我们希望在每次使用这个核心业务功能方法biz()之前,都能自动的执行一个周边功能方法before(),在使用这个核心业务功能方法biz()之后,都能自动的执行一个周边功能方法after()。

正常的步骤是,我们在AspectBiz类中,我们可以定义一个before()和after()方法,每次调用biz()方法时,都在前启用before()方法,在后启用after()方法。假如只有在这一个能需要使用这些周边的功能,这样的方式还好。但是假如有很多的类需要使用很多的这种周边功能,我们会发现代码耦合度增高,代码的重复度也增加了。而利用AOP思想,可以处理这类问题:

我们再定义一个AspectAOP类,这个类就是专门用来定义这些切面功能方法的,我们利用AOP思想,就可以把核心功能和切面功能分开,只需要在配置文件中加以配置即可实现在AspectBiz类运行某个方法前后,使用某个切面功能。代码如下:

我们先定义一个我们日常使用的核心业务类AspectBiz:

public class AspectBiz {
public void biz() {
System.out.println("AspectBiz!");
}
}
之后,我们定义一个切面业务类PAspect:

public class PAspect {
public void before() {
System.out.println("PAspect before");
}

public void after() {
System.out.println("PAspect after");
}
}
之后我们配置好XML文件:

<bean id="pAspect" class="parafeel.aspect.PAspect"></bean>
<bean id="aspectBiz" class="parafeel.aspect.AspectBiz"></bean>

<aop:config>
   		<aop:pointcut  id="pPointCut" expression="execution(* parafeel.aspect.AspectBiz.*(..))"/>
   
   		<aop:aspect id="pAspectAOP" ref="pAspect">
   			<aop:before method="before" pointcut-ref="pPointCut"/>
   			<aop:after method="after" pointcut-ref="pPointCut"/>
   		</aop:aspect>
   </aop:config>

配置文件中,我们可以看到,我们是在aop:config中配置切面信息的。aop:pointcut,设置核心功能的切点处,我们的切面功能都是在这个切点周围实现的。上面的:

<aop:pointcut  id="pPointCut" expression="execution(* parafeel.aspect.AspectBiz.*(..))"/>
id为切点的名词,expression则指定具体的切点位置,切点位置的描述有很多种,上面指的是parafeel包下的aspect包下的AspectBize类下的所有方法。利用这段文字可以配置各种不同的信息,指定不同的位置、方法、类等等。

<aop:aspect id="pAspectAOP" ref="pAspect">
   		<aop:before method="before" pointcut-ref="pPointCut"/>
   		<aop:after method="after" pointcut-ref="pPointCut"/>
   	</aop:aspect>
而aop:aspect则是用来描述切面的,上面的id是切面名称,ref指切面对应的bean名称。里面配置的aop:before则是配置在切点前执行的方法,其中method指的是方法名,pointcut-ref指的是对应的切点名称。同理,aop:after则是配置在切点后执行的方法,其中method指定方法名,pointcut-ref指的是对用的切点名称。

我们利用Junit测试下,下面的UniteTestBase是为了设置好配置文件,方便之后进行单元测试时使用:

public class UnitTestBase {

private ClassPathXmlApplicationContext context;

private String springXmlpath;

public UnitTestBase() {}

public UnitTestBase(String springXmlpath) {
this.springXmlpath = springXmlpath;
}

@Before
public void before() {
if (springXmlpath.equals("")) {
springXmlpath = "classpath*:applicationContext.xml";
}
try {
context = new ClassPathXmlApplicationContext(springXmlpath.split("[,\\s]+"));
context.start();
} catch (BeansException e) {
e.printStackTrace();
}
}

@After
public void after() {
context.destroy();
}

@SuppressWarnings("unchecked")
protected <T extends Object> T getBean(String beanId) {
try {
return (T)context.getBean(beanId);
} catch (BeansException e) {
e.printStackTrace();
return null;
}
}

protected <T extends Object> T getBean(Class<T> clazz) {
try {
return context.getBean(clazz);
} catch (BeansException e) {
e.printStackTrace();
return null;
}
}

}之后是单元测试:
public class tSpring extends UnitTestBase{
public tSpring() {
super("classpath:applicationContext.xml");
}

@Test
public void testS() {
AspectBiz biz = super.getBean("aspectBiz");
biz.biz();
} 我们在运行之后可以得到的结果为:很明显的可以看到,这个简单的AOP实现已经成功了。
另外,在XML配置文件中,还有很多其他的配置项,例如除了after之外,还有after-returning、after-throwing,分别是切点正常运行后执行的after-returning,在切点运行时抛出异常的after-throwing。其中
4000
这些配置项中,after和after-returning是按配置文件中的配置顺序而执行的。
除了这些after和before项,还有around项,用来表示在切点执行前和执行后:

<aop:around method="around" pointcut-ref="pPointCut"/>
在配置around时,需要主要方法的参数:
public Object around(ProceedingJoinPoint pjp) {
Object object = null;
try {
System.out.println("PAspect around1");
object = pjp.proceed();
System.out.println("PAspect around2");
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return object;
}运行后会发现,上面的round1和round2,依次输出。

除了上面了,我们还可以在切面方法中,去得到切点方法处的参数,比如我们在切点处有一个init方法:
public class AspectBiz {
public void biz() {
System.out.println("AspectBiz!");
}

public void init(String bizName,int times) {
System.out.println("AspectBiz,bizName :" + bizName + " times: " + times );
}
}


我们在切面中定义一个方法

public class PAspect {
public void before() {
System.out.println("PAspect before");
}
public void after() {
System.out.println("PAspect after");
}
public Object detail(ProceedingJoinPoint pjp,String bizName,int times) throws Throwable {
System.out.println(bizName +" " +times);
StopWatch clock = new StopWatch("Deatail for1 " + bizName + " and " + times + " ");
try {
clock.start();
return pjp.proceed();
} finally {
clock.stop();
System.out.println(clock.prettyPrint());
}
}

}

我们在xml中配置时,制定好切面中的某个方法,对应切点的位置:
<aop:config>
<aop:pointcut id="pPointCut" expression="execution(* parafeel.aspect.AspectBiz.*(..))"/>

<aop:aspect id="pAspectAOP" ref="pAspect">
<aop:before method="before" pointcut-ref="pPointCut"/>

<aop:around method="detail" pointcut=
"execution(* parafeel.aspect.AspectBiz.init(String,int)) and args(bizName,times))"/>
<aop:after method="after" pointcut-ref="pPointCut"/>

</aop:aspect>
</aop:config>

那么我们在执行切点处的方法时,会自动的调用切面的方法,实现AOP:
@Test
public void testS() {
AspectBiz biz = super.getBean("aspectBiz");
biz.init("para", 3);
}

执行结果为:



上面的示例,我们就可以看到切面方法在切点周围执行的时候,还可以获取切点周围的参数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  aop 编程 spring