使用JAVA Spring AOP实现动态代理

开启AOP配置

package com.example.springdemo.aopdemo;

import com.example.springdemo.aopdemo.Aspect.LogAspect;
import org.springframework.context.annotation.*;

@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
    @Bean
    public AspectService aspectService() {
        return new AspectServiceImpl();
    }
    @Bean
    public LogAspect logAspect() {
        return new LogAspect();
    }
}

使用@Configuration注解一个类时,@Configuration类本身被注册为一个bean定义,类中所有声明的@Bean方法也被注册为bean定义。
@EnableAspectJAutoProxy表示启动AspectJ的自动代理
Spring默认的main方法的类注解@SpringBootApplication默认会设置bean扫描范围为主类所在package下的所有类. 所以正常开发的时候使用@Service这类注解注入就可以被扫描到. 但因为我打算在main方法测试功能的时候中使用@Configuration配置的IOC容器,所以 AopConfig里面的两个Bean注入是必要的. 当然也可以配置@ComponentScan(basePackages = "com.xxx")

package com.example.springdemo.aopdemo.Aspect;
import com.example.springdemo.aopdemo.AopConfig;
import com.example.springdemo.aopdemo.AspectService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component // 切面本身也是一个bean,需要注入到容器中
@Aspect  // 声明为一个切面
public class LogAspect {
    @Pointcut("execution(public int com.example.springdemo.aopdemo.AspectService.*(..))")
    // 切入点表达式,切点描述带包名,一般都很长,写成方法形式可以复用,增加可读性和可维护性
    public void pointCut(){
    }
    @Before("pointCut()")
    // 前置通知,在目标方法运行之前执行
    public void logStart(JoinPoint joinPoint){
        System.out.println(joinPoint.getSignature().getName() + " 运行开始,参数列表是:{"+ Arrays.asList(joinPoint.getArgs()) +"}");
    }
    @After("pointCut()")
    // 后置通知,在目标方法运行之后但在返回之前执行
    public void logEnd(JoinPoint joinPoint){
        System.out.println(joinPoint.getSignature().getName() + " 运行结束");
    }
    @AfterReturning(value = "pointCut()", returning = "result")
    // 返回通知,在方法正常返回之后执行
    public void logReturn(JoinPoint joinPoint, Object result){
        System.out.println(joinPoint.getSignature().getName() + " 正常返回,运行结果:{"+result+"}");
    }
    @AfterThrowing(value = "pointCut()", throwing = "exception")
    // 异常通知,在方法抛出异常之后执行
    public void logException(JoinPoint joinPoint, Exception exception){
        System.out.println(joinPoint.getSignature().getName() + " 异常,异常信息:{"+exception+"}");
    }
    public static void main(String[] args) {
        // 通过注解配置类加载spring容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
        // 获取bean,因为配置了EnableAspectJAutoProxy表示开启AOP,所以会自动创建代理对象,此时获取的是代理对象
        AspectService aspectService = context.getBean(AspectService.class);
        aspectService.save(new AspectBean());
    }
}

Spring的AnnotationConfigApplicationContext部分,是Spring3.0中新增的。 这是一个强大的ApplicationContext实现,不仅能解析@Configuration注解类,也能解析@Componnet注解的类和使用JSR 330标准注解的类。当提供@Component和JSR-330类时,它们被注册为bean定义,并且假定在必要时在这些类中使用DI元数据,例如@Autowired@Inject

其他基础类

先写一个最基础的service
实体类

public class AspectBean {  
}

service接口

package com.example.springdemo.aopdemo;
import com.example.springdemo.aopdemo.Aspect.AspectBean;
public interface AspectService {
    public int save(AspectBean aspectBean);
}

service实现

package com.example.springdemo.aopdemo;
import com.example.springdemo.aopdemo.Aspect.AspectBean;
import org.springframework.stereotype.Service;
@Service
public class AspectServiceImpl implements AspectService {
    @Override
    public int save(AspectBean aspectBean) {
        System.out.println("save");
        return 1;
    }
}