Aop
AOP:面向切面编程,相对于OOP面向对象编程。
Spring的AOP的存在目的是为了解耦。AOP可以让一组类共享相同的行为。在OOP中
只能通过继承类和实现接口,来使代码的耦合度增强,且类继承只能为单继承,阻碍更多行为
添加到一组类上,AOP 弥补了OOP的不足。
1.添加依赖(版本要对应,不然报错)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lglg</groupId>
<artifactId>spring-demo01</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.编写拦截规则的注解(注解方式,灵活)
package com.lglg.annotation;
import java.lang.annotation.*;
/**
* Date:2020/8/9
*
* @author:lg
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {
String name();
}
这里讲下注解,注解本身是没有功能的,就和xml一样。注解和xml都是一种元数据,
元数据即解释数据的数据,这就是所谓配置。
注解的功能来自用这个注解的地方。
3. 编写相应拦截类演示效果
@Service
public class DemoAnnotationService {
@Action(name = "我是add")
public void add(){
}
}
@Service
public class DemoMethodService {
public void add(){
}
}
4. 编写切面
package com.lglg.aop;
import com.lglg.annotation.Action;
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;
/**
* Date:2020/8/9
*
* @author:lg
*/
@Aspect // 声明是一个切面
@Component // 交给Spring管理
public class LogAspect {
@Pointcut("@annotation(com.lglg.annotation.Action)") // 注解式
// @Pointcut(value = "execution(* com.lglg.springdemo01..*.*(..))") // 方法规则式
public void annotationPointCut(){
// 这里没有做什么,仅仅声明为一个切点
};
@After("annotationPointCut()") // 方法执行之后执行
public void after(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method =
signature.getMethod();
// 获取方法上的注解
Action annotation = method.getAnnotation(Action.class);
// 获取注解上name属性的值
// String name = annotation.name();
String name = method.getName();
System.out.println("注解式拦截" + name);
}
/**
* 1、execution(): 表达式主体。
2、第一个*号:表示返回类型,*号表示所有的类型。
3 、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包, com.sample.service.impl包、子孙包下所有类的方法。
4、第二个*号:表示类名,*号表示所有的类。
5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
6、总的来说,要多看切面表达式,如果只是应用,下面表达式几乎式万能的
*/
@Before("execution(* com.lglg.springdemo01..*.*(..)))")
// @Before("annotationPointCut()") // 可以用上面的切入点, 选用切入点表达式
public void before(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 获取方法名
String name = method.getName();
System.out.println("方法式规则拦截" + name);
}
}
5.编写配置类
package com.lglg.config;
import com.lglg.springdemo01.FunctionService;
import com.lglg.springdemo01.UserFunctionService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* Date:2020/8/9
*
* @author:lg
*/
@Configuration
@ComponentScan("com.lglg")// 扫面相应的包路径
@EnableAspectJAutoProxy // 注解开启Spring对AspectJ代理的支持
public class LgConfig {
// @Bean// 通过该注解将该方法上的bean注入到Spring容器中
// public FunctionService functionService(){
// return new FunctionService();
// }
//
// @Bean
// public UserFunctionService userFunctionService(){
// return new UserFunctionService();
// }
}
6. 测试
package com.lglg.demoTest;
import com.lglg.config.LgConfig;
import com.lglg.springdemo01.DemoAnnotationService;
import com.lglg.springdemo01.DemoMethodService;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* Date:2020/8/9
*
* @author:lg
*/
public class Demo02 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LgConfig.class);
DemoAnnotationService annotationService = context.getBean(DemoAnnotationService.class);
DemoMethodService demoMethodService = context.getBean(DemoMethodService.class);
annotationService.add();
demoMethodService.add();
context.close();
}
}
结果:
小结:
上面的切点可以引用注解式,也可以引用方法式