AOP 面向切面
AOP面向切面 = OOP面向对象编程
Spring的AOP存在的目的是为了解耦,AOP可以让一组一类共享相同的行为,
在OOP中只能通过几次类和实现接口,来实现代码耦合度增强。且类继承只能为单继承,阻碍更多行为添加到一组类上,AOP弥补了OOP的不足
Spring支持AspectJ的注解式切面编程
使用@Aspect声明是一个切面
使用@After,@Before,@Around定义建言(advice),可直接将拦截规则(切点)作为参数
其中@After,@Before,@Around参数的拦截规则为切点(PointCut),为了使切点复用。可以使用@pointCut专门拦截规则
然后在@After,@Before,@Around的参数中调用
其中符合条件的每一个被拦截处为连接点JoinPoint
Spring本身在事务处理@Transcational和数据库@Caheable 上,都使用了这种形式的拦截
附代码
配置好maven架包 Spring aop支持及AspectJ依赖
<!-- Spring aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<!-- Spring aspectj -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
接口文件 拦截规则的注解
注解本身没有功能,和xml一样。注解和xml都是一种元数据,元数据即解释数据的数据 ,即所谓的配置
注解的功能来自用这个注解的地方
package com.example.demo.aop;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {
String name();
}
使用注解的被拦截类
package com.example.demo.aop;
import org.springframework.stereotype.Service;
@Service
public class DemoAnnotationService {
@Action(name="注解式拦截的add操作")
public void add(){}
}
使用方法规则被拦截类
package com.example.demo.aop;
import org.springframework.stereotype.Service;
@Service
public class DemoMethodService {
public void add(){}
}
切面类
@Before("execution(* com.example.demo.aop.DemoMethodService.*(..))") 规则描述
execution :表示执行方法的时候会触发
" * " :星号表示任意返回类型的方法
com.example.demo.aop.DemoMethodService.*(..) 被代理的方法,这里也可以不用写实现类的方法,直接写接口方法
(..):任意的参数
package com.example.demo.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect // 注解声明一个切面
@Component // @Conmponent让切面成为一个Spring容器管理的Bean
public class LogAspect {
@Pointcut("@annotation(com.example.demo.aop.Action)") //通过Pointcut注解声明切点
public void annotationPoinCut(){};
@After("annotationPoinCut()") // 注解声明一个建言,并使用PointCut定义的切点
public void after(JoinPoint joinPoint){
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
Action action = method.getAnnotation(Action.class);
System.err.println("注解式拦截"+action.name()); // 通过反射可以获得注解属性
}
@Before("execution(* com.example.demo.aop.DemoMethodService.*(..))")
public void before(JoinPoint joinPoint){
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
System.err.println("方法规则式拦截"+method.getName());
}
}
配置类
使用EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持
package com.example.demo.aop;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.example.demo.aop")
@EnableAspectJAutoProxy
public class AopConfig {
}
启动
package com.example.demo;
import com.example.demo.aop.AopConfig;
import com.example.demo.aop.DemoAnnotationService;
import com.example.demo.aop.DemoMethodService;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
DemoMethodService demoMethodService = context.getBean(DemoMethodService.class);
DemoAnnotationService demoAnnotationService = context.getBean(DemoAnnotationService.class);
demoMethodService.add();
demoAnnotationService.add();
context.close();
}
}