对于jdk5.0以后,java提供了注解技术,而Aspectj就是基于注解的AOP技术。那有人可能会问,那基于Aspectj和基于Schema两种谁更好一些呢?那我会说,没有谁好谁不好,这两种形式都比较简洁,就好像用中文写了一个伊索寓言和用英文写了一个伊索寓言一样。
1、基于Schema的AOP都涉及到哪些注解?
使用Aspectj之前,我们需要maven项目添加一个依赖:
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
我们看一下相关的注解:
- @Aspect,切面类的注解,表明此类是切面类,可以使用增强。
- @Before,前置增强的注解,参数argNames可以将目标方法的参数获取到前值增强方法的参数上,配合表达式args使用;参数value是切点的表达式。
- @AfterReturning,后置增强的注解,参数argNames同上;参数pointcut可以引入切点方法;参数returning获取到目标方法的返回值并给增强方法传参。参数value是切点的表达式。
- @AfterThrowing,异常抛出增强的注解,参数argNames同上;参数pointcut同上;参数value同上;参数throwing获取目标方法的异常并传参给增强。
- @Around,环绕增强的注解,参数argNames同上,参数value同上。
- @DeclareParents,引介增强属性级别的注解,value同上,参数defaultImpl是接口的默认实现类。
- @Pointcut,切点的注解,参数argNames同上,参数value同上。
2、可以可以将这些增强放到同一个代码中体现?
请看代码:
Lecturer.java(目标类)
package com.spring.test;
/**
* 讲师类,具有上课方法
* @author beijingduanluo
*
*/
public class Lecturer {
public void classBegin(){
System.out.println("讲师传授新技术,同学们讨论很激烈!");
}
}
LecturerAdvice.java(切面)
package com.spring.test;
import org.aspectj.lang.ProceedingJoinPoint;
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.DeclareParents;
import org.aspectj.lang.annotation.Pointcut;
/**
* 增强类
* @author beijingduanluo
*
*/
@Aspect
public class LecturerAdvice {
// 引介增强,使用接口类型的属性
@DeclareParents(value="com.spring.test.Lecturer",defaultImpl=SchoolImpl.class)
public School school;
/**
* 切点方法,避免每个增强都配置切点表达式
*/
@Pointcut("target(com.spring.test.Lecturer) and execution(public void classBegin())")
public void pointcut() {}
/**
* 前置增强的方法,直接配置切点方法
*/
@Before("pointcut()")
public void beforeAdvice() {
System.out.println("前置增强");
}
/**
* 后置增强的方法,直接配置切点方法
*/
@AfterReturning("pointcut()")
public void afterAdvice() {
System.out.println("后置增强");
}
/**
* 环绕增强的方法,直接配置切点方法
*/
@Around("pointcut()")
public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕增强前");
pjp.proceed();
System.out.println("环绕增强后");
}
/**
* 异常抛出增强的方法,直接配置切点方法
*/
@AfterThrowing("pointcut()")
public void throwsAdvice() {
System.out.println("异常抛出增强");
}
}
School.java(目标接口)
package com.spring.test;
public interface School {
public void setRest(boolean rest);
public boolean getRest();
}
SchoolImpl.java(目标接口默认实现类)
package com.spring.test;
public class SchoolImpl implements School {
private boolean rest;
public void setRest(boolean rest) {
// TODO Auto-generated method stub
this.rest = rest;
}
public boolean getRest() {
// TODO Auto-generated method stub
return rest;
}
}
ApplicationContext.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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 配置目标类 -->
<bean id="lecturer" class="com.spring.test.Lecturer"></bean>
<!-- 配置增强类 -->
<bean id="advice" class="com.spring.test.LecturerAdvice"></bean>
</beans>
SpringTest.java(测试类)
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.test.Lecturer;
import com.spring.test.School;
public class SpringTest{
public static void main(String[] args){
ApplicationContext content = new ClassPathXmlApplicationContext("applicationcontext.xml");
Lecturer lecturer = (Lecturer) content.getBean("lecturer");
// 调用目标方法,查看增强
lecturer.classBegin();
// 测试目标方法使用引介了School接口
School school = (School) lecturer;
school.setRest(true);
System.out.println(school.getRest());
}
}
控制台
环绕增强前
前置增强
讲师传授新技术,同学们讨论很激烈!
环绕增强后
后置增强
true
在配置文件中,除了配置目标类的bean和切面的bean,还要使用标签<aop:aspectj-autoproxy>
让注解自动代理。
3、spring的总结
至此为止,我们spring的两个大核心IOC和AOP已经完全学完了,但仅仅是我们的研究告一段落,spring的优美之处已经可圈可点之处远远不止这些。非常多的工程师不断地研究spring的源码,希望能在源码中学到东西,而且他们也在不断地从spring框架中获取到知识。
spring是java编程的一个纪元,他的外表,他的内层无不令人惊叹。我希望同学们学习spring的步伐不要停止,spring会给我们带来你想不到的成果。