@ghimi
2018-08-02T07:23:08.000000Z
字数 4526
阅读 1034
spring
AOP : 面向切面编程,相对于OOP面向对象编程.
Spring 的 AOP 的存在目的是为了解耦.AOP可以让一组类共享相同的行为.在OOP中只能通过继承类和实现接口,来时代码的耦合度增强,且类继承只能为单继承,阻止了更多的类添加到一组类上,AOP弥补了OOP的不足.
Spring 支持 AspectJ 的注解是切面编程.
1. 使用@Aspect 声明是一个切面.
2. 使用@After,@Before,@Around 定义建言(advice),可直接将拦截规则(切点作为参数).
3. 其中@After,@Before,@Around 参数的拦截规则为切点(PointCut),为了是切点复用,可使用@PointCut 专门定义拦截规则,然后再@After,@Before,@Around 的参数中调用,
4. 其中符合条件的每一个被拦截处为连接点(JoinPoint)
本节示例将演示基于注解拦截和基于方法规则拦截的两种方式,演示一种模拟记录操作的日志系统的实现.其中注解式拦截能够很好的控制要拦截的粒度和获得更丰富的信息,Spring本身在事务处理(@Transcational)和数据缓冲(@Cacheable等)上面都使用此种形式的拦截.
2.1 首先编写注解类
package spring4.ch1.aop;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)//其实没有必要添加@Document的注解@Documentedpublic @interface Action {String name();}
2.2 对需要拦截方法添加注解
package spring4.ch1.aop;import org.springframework.stereotype.Service;@Service//对需要切入的方法上添加自定义的注解public class DemoAnnotationService {@Action(name="注解式拦截的add操作")public void add(){System.out.println("DemoAnnotation 类的add操作本身!");}@Factor(path = "Annotation from Factor and delete() method!")public void delete(){System.out.println("DemoAnnotation 类的delete操作本身");}}
3.1 直接编写类(不需要任何其他操作)
package spring4.ch1.aop;import org.springframework.stereotype.Service;@Service//直接编写类,不需要其他任何操作public class DemoMethodService {public void add(){}}
在切面中,我们使用 @After 和 @Before,将两种拦截切面都做了拦截
package spring4.ch1.aop;import java.lang.reflect.Method;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;@Aspect@Componentpublic class LogAspect {@Pointcut("@annotation(spring4.ch1.aop.Action)")public void annotationPointCut(){}@Pointcut("@annotation(spring4.ch1.aop.Factor)")public void annotationPointCut2(){}@Before("annotationPointCut()")public void after(JoinPoint joinPoint){MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();Action action = method.getAnnotation(Action.class);System.out.println("注解式拦截 "+ action.name());}@Before("annotationPointCut2()")public void after2(JoinPoint joinPoint){MethodSignature signature = (MethodSignature)joinPoint.getSignature();Method method = signature.getMethod();Factor factor = method.getAnnotation(Factor.class);System.out.println("注解式拦截2 "+ factor.path());}@After("execution(* spring4.ch1.aop.DemoMethodService.*(..))")public void before(JoinPoint joinPoint) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();System.out.println("方法规则式拦截, " + method.getName());}}
在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点"例如定义切入点表达式 execution(* com.sample.service.impl..*.*(..))execution()是最常用的切点函数,其语法如下所示:整个表达式可以分为五个部分:1、execution(): 表达式主体。2、第一个*号:表示返回类型,*号表示所有的类型。3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。4、第二个*号:表示类名,*号表示所有的类。5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
package com.example.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ConfigurableApplicationContext;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.ComponentScan;import spring4.ch1.aop.DemoAnnotationService;import spring4.ch1.aop.DemoMethodService;import spring4.ch1.di.UseFunctionService;@SpringBootApplication@ComponentScan("spring4.ch1")@EnableAspectJAutoProxy//使用扫描注解方法建立context//然后执行我们的几个测试方法public class Demo1Application {public static void main(String[] args) {// ConfigurableApplicationContext run = SpringApplication.run(Demo1Application.class, args);AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo1Application.class);String[] beanDefinitionNames = context.getBeanDefinitionNames();for (String string : beanDefinitionNames) {System.out.println(string);}UseFunctionService bean = context.getBean(UseFunctionService.class);// System.out.println(bean.sayHello("di"));DemoAnnotationService bean2 = context.getBean(DemoAnnotationService.class);DemoMethodService bean3 = context.getBean(DemoMethodService.class);bean3.add();bean2.add();bean2.delete();context.close();}}
测试结果输出
方法规则式拦截, add注解式拦截 注解式拦截的add操作DemoAnnotation 类的add操作本身!注解式拦截2 Annotation from Factor and delete() method!DemoAnnotation 类的delete操作本身