概念
摘自:百度百科
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
动态代理
代理模式:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展
jdk动态代理
需要实现接口
public interface UserInterface {
void test();
void run();
}
public class UserService implements UserInterface {
@Override
public void test(){
System.out.println("test");
}
@Override
public void run() {
System.out.println("run");
}
}
public class UserInterfaceInvocationHandler implements InvocationHandler {
private UserInterface userInterface;
public UserInterfaceInvocationHandler(UserInterface userInterface){
this.userInterface = userInterface;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object value = method.invoke(userInterface, args);
System.out.println("after");
return value;
}
}
public class JdkProxyTest {
public static void main(String[] args) {
UserInterface userInterfaceBase = new UserService();
UserInterfaceInvocationHandler userInterfaceInvocationHandler = new UserInterfaceInvocationHandler(userInterfaceBase);
UserInterface userInterface = (UserInterface) Proxy.newProxyInstance(JdkProxyTest.class.getClassLoader(), new Class[]{UserInterface.class}, userInterfaceInvocationHandler);
userInterface.test();
}
}
cglib动态代理
public class CgLibProxyTest {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallbacks(new Callback[]{
(MethodInterceptor) (obj, method, args1, proxy) -> {
System.out.println("before");
Object value = proxy.invokeSuper(obj, args1);
System.out.println("after");
return value;
}, NoOp.INSTANCE
});
//cjlib callback 过滤
enhancer.setCallbackFilter(method -> {
//test方法使用第一个callback,其他方法使用第二个callback
if("test".equals(method.getName())){
return 0;
}
return 1;
});
UserService userService = (UserService)enhancer.create();
userService.test();
System.out.println("--------------------------------------");
userService.run();
}
}
示例
https://gitee.com/luoye/examples/tree/main/aop/simpleAop
Spring AOP
ProxyFactory
在Spring中对代理进行了封装,封装后的类叫:ProxyFactory,使用方法如下:
public class SimpleProxyFactoryTest {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new UserService());
proxyFactory.addAdvice((MethodInterceptor) invocation -> {
System.out.println("before");
Object value = invocation.proceed();
System.out.println("after");
return value;
});
UserService userService = (UserService) proxyFactory.getProxy();
userService.test();
}
}
通过使用ProxyFactory我们不用再关心到底使用cjlib换算jdk动态代理了,ProxyFactory会自己判断。
Advice分类
类型 | 说明 |
---|---|
Before Advice | 方法执行之前执行 |
After Returning Advice | 方法执行之后执行 |
After Throwing Advice | 方法抛出异常后执行 |
After (Finally) Advice | 方法执行完finally之后执行,比return更往后 |
Around Advice | 可以自定义执行顺序 |
/**
* 方法执行之后执行
*
* @author lmm
* @date 2022-03-23
*/
public class CustomAfterReturningAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("after returning");
}
}
/**
* 抛出异常之后执行
*
* @author lmm
* @date 2022-03-23
*/
public class CustomAfterThrowingAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
try{
return invocation.proceed();
}catch (Exception e){
System.out.println("after throwing msg: "+e.getMessage());
return null;
}
}
}
/**
* 方法执行前、后执行
*
* @author lmm
* @date 2022-03-23
*/
public class CustomAroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("around before");
Object value = invocation.proceed();
System.out.println("around after");
return value;
}
}
/**
* 方法执行之前执行
*
* @author lmm
* @date 2022-03-23
*/
public class CustomBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before");
}
}
/**
* 测试advice
*
* @author lmm
* @date 2022-03-23
*/
public class AdviceProxyFactoryTest {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new UserService());
proxyFactory.addAdvice(new CustomAroundAdvice());
proxyFactory.addAdvice(new CustomBeforeAdvice());
proxyFactory.addAdvice(new CustomAfterReturningAdvice());
proxyFactory.addAdvice(new CustomAfterThrowingAdvice());
UserService userService = (UserService) proxyFactory.getProxy();
userService.test();
System.out.println("-----------------------");
userService.testThrowing();
}
}
Advisor
一个Advicsor是由一个Pointcut和一个Advice组成的,通过Pointcut可以指定需要被代理的逻辑
/**
* 简单测试Advisor
*
* @author lmm
* @date 2022-03-23
*/
public class SimpleAdvisorTest {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new UserService());
proxyFactory.addAdvisor(new PointcutAdvisor() {
@Override
public Pointcut getPointcut() {
return new StaticMethodMatcherPointcut() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return "test".equals(method.getName());
}
};
}
@Override
public Advice getAdvice() {
return new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
return invocation.proceed();
}
};
}
@Override
public boolean isPerInstance() {
return false;
}
});
UserService userService = (UserService) proxyFactory.getProxy();
userService.test();
System.out.println("------------------");
userService.run();
}
}
ProxyFactory示例
https://gitee.com/luoye/examples/tree/main/aop/proxyFactoryTest
ProxyFactoryBean
Spring创建一个AOP代理的基本方法是使用ProxyFactoryBean,它提供了切点和增强的控制能力,常用配置如下
属性名称 | 说明 |
---|---|
target | 代理的目标对象 |
proxyInterfaces | 代理要实现的接口 |
interceptorNames | 植入目标的Advice |
singleton | 返回的代理是否为单例,默认:true |
optimize | 是否优化,设置为true是,强制使用cglib |
使用示例
/**
* 用户service
*
* @author lmm
* @date 2022-03-23
*/
public class UserService {
public void test(){
System.out.println("test");
}
}
/**
* ProxyFactoryBean配置
*
* @author lmm
* @date 2022-03-23
*/
@Configuration
public class ProxyFactoryBeanConfig {
/**
* 方法执行前执行
* @return
*/
@Bean
public MethodInterceptor beforeAdvice(){
return new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
return invocation.proceed();
}
};
}
/**
* 用户service代理对象
* @return
*/
@Bean
public ProxyFactoryBean userServiceProxy(){
UserService userService = new UserService();
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(userService);
proxyFactoryBean.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object value = invocation.proceed();
System.out.println("after");
return value;
}
});
proxyFactoryBean.setInterceptorNames("beforeAdvice");
return proxyFactoryBean;
}
}
/**
* ProxyFactoryBean测试
*
* @author lmm
* @date 2022-03-23
*/
public class ProxyFactoryBeanTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProxyFactoryBeanConfig.class);
UserService userService = context.getBean("userServiceProxy",UserService.class);
userService.test();
}
}
BeanNameAutoProxyCreator
通过指定bean的名字,来对该bean进行代理
示例:
/**
* 用户service
*
* @author lmm
* @date 2022-03-23
*/
@Component
public class UserService {
public void test(){
System.out.println("test");
}
}
/**
* bean名称代理配置
*
* @author lmm
* @date 2022-03-23
*/
@Configuration
@ComponentScan("show.lmm.demo.beanNameAutoProxy")
public class BeanNameAutoProxyConfig {
/**
* 方法执行前执行
* @return
*/
@Bean
public MethodInterceptor beforeAdvice(){
return new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
return invocation.proceed();
}
};
}
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator(){
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
beanNameAutoProxyCreator.setBeanNames("user*");
beanNameAutoProxyCreator.setInterceptorNames("beforeAdvice");
return beanNameAutoProxyCreator;
}
}
/**
* bean名称代理测试
*
* @author lmm
* @date 2022-03-23
*/
public class BeanNameAutoProxyTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanNameAutoProxyConfig.class);
UserService userService = context.getBean("userService",UserService.class);
userService.test();
}
}
DefaultAdvisorAutoProxyCreator
DefaultAdvisorAutoProxyCreator会直接查找所有Advisor类型的Bean,根据Advisor中的Pointcut和Advice信息,确定要代理的Bean以及代理的逻辑。
示例:
/**
* 用户service
*
* @author lmm
* @date 2022-03-23
*/
@Component
public class UserService {
public void test(){
System.out.println("test");
}
public void run(){
System.out.println("run");
}
}
/**
* 默认Advisor自动代理配置
*
* @author lmm
* @date 2022-03-23
*/
@Configuration
@ComponentScan("show.lmm.demo.defaultAdvisorAutoProxy")
public class DefaultAdvisorAutoProxyConfig {
/**
* 默认切点advisor
*
* @return
*/
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
NameMatchMethodPointcut nameMatchMethodPointcut = new NameMatchMethodPointcut();
nameMatchMethodPointcut.addMethodName("test");
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
defaultPointcutAdvisor.setPointcut(nameMatchMethodPointcut);
defaultPointcutAdvisor.setAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
return invocation.proceed();
}
});
return defaultPointcutAdvisor;
}
/**
* 默认Advisor自动代理
*
* @return
*/
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
}
/**
* 默认Advisor自动代理测试
*
* @author lmm
* @date 2022-03-23
*/
public class DefaultAdvisorAutoProxyTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DefaultAdvisorAutoProxyConfig.class);
UserService userService = context.getBean("userService", UserService.class);
userService.test();
System.out.println("------------------------");
userService.run();
}
}
注解方式使用aop
概念
- Aspect:切面,可以在切面中定义Pointcut、Advice等。
- Join point:连接点,表示一个程序在执行过程中的一个点,在Spring aop中,一个连接点通常表示一个方法的直销。
- Advice:通知,表示在特定连接点上采取的动作。在Spring aop中,会用Interceptor拦截器来实现Advice,并且在连接点周围维护一个Interceptor链。
- Pointcut:切点,用来匹配一个或多个连接点,Advice与切点表达式是关联着一起的,Advice将会执行在和切点表达式所匹配的连接点上。
- Introduction:可以使用@DeclareParents来给所匹配的类增加一个接口,并指定一个默认实现。
- Target object:目标对象,被代理对象。
- Aop proxy:表示代理工作,在spring中,要么用jdk动态代理,要么用cglib代理。
- Weaving:织入,表示创建代理对象的动作,可以发生在编译期(Aspejctj),或运行时(spring aop)
spring aop 注解
注解 | 说明 |
---|---|
@Aspect | 定义切面 |
@Pointcut | 定义切点 |
@Before | 方法执行前,执行aop逻辑 |
@Around | 方法执行前/后,执行aop逻辑 |
@After | 方法执行后,执行aop逻辑 |
@AfterReturning | 方法返回前(finally),执行aop逻辑 |
@AfterThrowing | 方法执行异常时,执行aop逻辑 |
示例:
build.gradle 中引入依赖
dependencies {
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version: '2.6.4'
}
/**
* 用户service
*
* @author lmm
* @date 2022-03-23
*/
@Component
public class UserService {
public void test(){
System.out.println("test");
}
public void run(){
System.out.println("run");
}
}
/**
* 自定义aop逻辑
*
* @author lmm
* @date 2022-03-23
*/
@Aspect
@Component
public class CustomAspect {
@Before("execution(public void show.lmm.demo.springAop.UserService.test())")
public void before(JoinPoint joinPoint){
System.out.println("before");
}
}
/**
* spring aop测试
*/
@SpringBootApplication
public class SpringAopTest {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringAopTest.class, args);
UserService userService = context.getBean("userService", UserService.class);
userService.test();
System.out.println("------------------------");
userService.run();
}
}
TargetSource
在Spring AOP中,被代理对象就是bean对象,是由BeanFactory创建出来的。Spring AOP中还提供了TargetSource机制,可以自定义逻辑来创建被代理对象。
示例:
/**
* 用户service
*
* @author lmm
* @date 2022-03-23
*/
@Component
public class UserService {
private String userName;
public UserService(String userName){
this.userName = userName;
}
public void test(){
System.out.println("test "+userName);
}
}
/**
* 被代理对象config
*
* @author lmm
* @date 2022-03-23
*/
@Configuration
public class TargetSourceConfig {
@Bean
public UserService userService(){
TargetSource targetSource = new TargetSource() {
@Override
public Class<?> getTargetClass() {
return UserService.class;
}
@Override
public boolean isStatic() {
return false;
}
@Override
public Object getTarget() throws Exception {
return new UserService("张三");
}
@Override
public void releaseTarget(Object target) throws Exception {
//对象池需要处理
}
};
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTargetSource(targetSource);
return (UserService) proxyFactoryBean.getObject();
}
}
/**
* 测试TargetSource
*
* @author lmm
* @date 2022-03-23
*/
public class TargetSourceTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TargetSourceConfig.class);
UserService userService = context.getBean("userService", UserService.class);
userService.test();
}
}
Introduction
用于将已有的类引入新的接口,并提供新的服务
示例:
/**
* Service
*
* @author lmm
* @date 2022-03-23
*/
public interface Service {
void test();
}
/**
* 用户service
*
* @author lmm
* @date 2022-03-23
*/
@Component
public class UserService implements Service{
@Override
public void test(){
System.out.println("test");
}
}
/**
* 扩展接口
*
* @author lmm
* @date 2022-03-23
*/
public interface ExtendInterface {
void run();
}
/**
* 扩展实现
*
* @author lmm
* @date 2022-03-23
*/
public class ExtendImpl implements ExtendInterface {
@Override
public void run() {
System.out.println("run");
}
}
/**
* 自定义切面
*
* @author lmm
* @date 2022-03-23
*/
@Aspect
@Component
public class CustomAspect {
@DeclareParents(value = "show.lmm.demo.introduction.UserService",defaultImpl = ExtendImpl.class)
public ExtendInterface extendService;
}
/**
* 测试Introduction
*
* @author lmm
* @date 2022-03-23
*/
@SpringBootApplication
public class IntroductionTest {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(IntroductionTest.class, args);
ExtendInterface extendInterface = context.getBean("userService", ExtendInterface.class);
UserService userService = context.getBean("userService", UserService.class);
extendInterface.run();
userService.test();
}
}
Spring AOP示例
https://gitee.com/luoye/examples/tree/main/aop/springAopDemo