Spring-AOP 深度剖析

Spring-AOP 深度剖析

www.tomblog.club 我的博客欢迎大家访问

一、AOP的应用场景

1.SpringBoot整合AOP,异步记录日志.

1.1 导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

1.2 编写自定义注解

import java.lang.annotation.*;

/**
 * @author Administrator
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
    String value() default "";
}

1.3 编写切面类记录日志

import lombok.Data;

/**
 * @author Administrator
 */
@Data
public class SysLogEntity {
    private String className;
    private String methodName;
    private String params;
    private Long exeuTime;
    private String remark;
    private String createDate;
}
import com.mayikt.springsource.annotaion.SysLog;
import com.mayikt.springsource.model.entity.SysLogEntity;
import com.mayikt.springsource.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 日志切面
 *
 * @author zx
 * @date 2022年01月15日 21:48
 */
//@EnableAspectJAutoProxy
@Aspect
@Component
@Slf4j
public class LogAop {


    @Autowired
    private SysLogService sysLogService;

    /**
     * 这里我们使用注解的形式
     * 当然,我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method
     * 切点表达式:   execution(...)
     */
    @Pointcut("@annotation(com.mayikt.springsource.annotaion.SysLog)")
    public void logPointCut() {
    }


    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        Object result = point.proceed();
        long time = System.currentTimeMillis() - beginTime;
        try {
            //实现保存日志逻辑
            saveLog(point, time);
        } catch (Exception e) {

        }
        log.info("响应结果:{}", result);
        return result;
    }


    private void saveLog(ProceedingJoinPoint joinPoint, long time) {

        // 获取方法的关键信息,类,包
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        SysLogEntity sysLogEntity = new SysLogEntity();
        sysLogEntity.setExeuTime(time);

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        sysLogEntity.setCreateDate(dateFormat.format(new Date()));

        SysLog sysLog = method.getAnnotation(SysLog.class);
        if (sysLog != null) {
            //注解上的描述
            sysLogEntity.setRemark(sysLog.value());
        }

        //请求的 类名、方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();

        sysLogEntity.setClassName(className);
        sysLogEntity.setMethodName(methodName);

        //请求的参数
        Object[] args = joinPoint.getArgs();
        try {
            List<String> list = new ArrayList<String>();
            for (Object o : args) {
                list.add(o.toString());
            }
            sysLogEntity.setParams(list.toString());
        } catch (Exception e) {

        }
        //改成异步(MQ)
        sysLogService.save(sysLogEntity);
    }

}

1.4 异步保存日志

import com.mayikt.springsource.model.entity.SysLogEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class SysLogService {
    @Async
    public boolean save(SysLogEntity sysLogEntity){
        // 这里就不做具体实现了
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("threadName:{},sysLogEntity=====>{}",Thread.currentThread().getName(),sysLogEntity.toString());
        return true;
    }
}

1.5 开启异步功能

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class SpringSourceApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringSourceApplication.class, args);
    }

}

2. AOP 5大通知

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.14</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
            <scope>compile</scope>
        </dependency>
        <!--        <dependency>-->
        <!--            <groupId>org.springframework.boot</groupId>-->
        <!--            <artifactId>spring-boot-starter-aop</artifactId>-->
        <!--        </dependency>-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
package com.mayikt.springsource.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

/**
 * 日志切面
 *
 * @author zx
 * @date 2022年01月16日 8:42
 */
@Component
@Aspect
@EnableAspectJAutoProxy
public class LogAop {

    ///**
    // * 这里我们使用注解的形式
    // * 当然,我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method
    // * 切点表达式:   execution(...)
    // */
    //@Pointcut("@annotation(com.mayikt.springsource.annotaion.SysLog)")
    //public void logPointCut() {
    //}
    
    @Pointcut("execution (* com.mayikt.springsource..*.*(..))")
    public void loginAop() {
    }

    @Before("loginAop()")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println(">>>>>>>前置通知<<<<<<<<<<< ");
    }

    @After("loginAop()")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println(">>>>>>>>后置通知<<<<<<<<<");
    }

    @Around("loginAop()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println(">>>>环绕通知之前执行...>>>>>>");
        Object proceed = joinPoint.proceed();// 执行目标方案
        System.out.println(">>>>环绕通知之后执行...>>>>>>");

        return proceed;
    }

    /**
     * 运行通知
     */
    @AfterReturning("loginAop()")
    public void afterReturning(JoinPoint joinPoint) {
        System.out.println("运行通知执行.....");
    }

    /**
     * 异常通知
     */
    @AfterThrowing("loginAop()")
    public void afterThrowing(JoinPoint joinPoint) {
        System.out.println(">>>>>异常通知");
    }
}

import java.lang.annotation.*;

/**
 * @author Administrator
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
    String value() default "";
}

2.1 通知执行顺序

2.1.1 没有抛异常
import com.sun.istack.internal.NotNull;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 用户控制类
 *
 * @author zx
 * @date 2022年01月16日 8:29
 */
@RestController
public class UserController {
    /**
     * NotNull 表示一个提示警告程序员注意空指针
     *
     * @param username 用户名称
     * @return username 用户名称
     */
    @GetMapping("/getUserInfo")
    public String getUserInfo(@NotNull String username) {
        System.out.println("username:"+username);
        return username;
    }

 打印结果:
>>>>环绕通知之前执行...>>>>>>
>>>>>>>前置通知<<<<<<<<<<< 
username:tom
运行通知执行.....
>>>>>>>>后置通知<<<<<<<<<
>>>>环绕通知之后执行...>>>>>>
2.1.2 抛出异常
import com.sun.istack.internal.NotNull;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 用户控制类
 *
 * @author zx
 * @date 2022年01月16日 8:29
 */
@RestController
public class UserController {
    /**
     * NotNull 表示一个提示警告程序员注意空指针
     *
     * @param username 用户名称
     * @return username 用户名称
     */
    @GetMapping("/getUserInfo")
    public String getUserInfo(@NotNull String username) {
        System.out.println("username:"+username);
        int i = 1/0;
        return username;
    }
}
打印结果:
>>>>环绕通知之前执行...>>>>>>
>>>>>>>前置通知<<<<<<<<<<< 
username:tom2
>>>>>异常通知
>>>>>>>>后置通知<<<<<<<<<
java.lang.ArithmeticException: / by zero

3.责任链设计模式

责任链模式怎么使用呢?

  • 一个接口或者抽象类
  • 每个对象差异化处理
  • 对象链(数组)初始化(连起来)

3.1 一个接口或者抽象类

这个接口或者抽象类,需要:

  • 有一个指向责任下一个对象的属性
  • 一个设置下一个对象的set方法
  • 给子类对象差异化实现的方法(如以下代码的doFilter方法)
public abstract class AbstractHandler {

    //责任链中的下一个对象
    private AbstractHandler nextHandler;

    /**
     * 责任链的下一个对象
     */
    public void setNextHandler(AbstractHandler nextHandler){
        this.nextHandler = nextHandler;
    }

    /**
     * 具体参数拦截逻辑,给子类去实现
     */
    public void filter(Request request, Response response) {
        doFilter(request, response);
        if (getNextHandler() != null) {
            getNextHandler().filter(request, response);
        }
    }

    public AbstractHandler getNextHandler() {
        return nextHandler;
    }

     abstract void doFilter(Request filterRequest, Response response);

}

3.2 每个对象差异化处理

责任链上,每个对象的差异化处理,如本小节的业务场景,就有参数校验对象、安全校验对象、黑名单校验对象、规则拦截对象

import com.mayikt.projecttest.responsibilitychain.AbstractHandler;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *  黑名单校验对象
 */
@Component
@Order(3) //校验顺序排第3
public class CheckBlackFilterObject extends AbstractHandler {

    @Override
    public void doFilter(HttpServletRequest request, HttpServletResponse response) {
        //invoke black list check
        System.out.println("校验黑名单");
    }
}
import com.mayikt.projecttest.responsibilitychain.AbstractHandler;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 参数校验对象
 **/
@Component
@Order(1) //顺序排第1,最先校验
public class CheckParamFilterObject extends AbstractHandler {

    @Override
    public void doFilter(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("非空参数检查");
    }
}
import com.mayikt.projecttest.responsibilitychain.AbstractHandler;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *  规则拦截对象
 */
@Component
@Order(4) //校验顺序排第4
public class CheckRuleFilterObject extends AbstractHandler {

    @Override
    public void doFilter(HttpServletRequest request, HttpServletResponse response) {
        //check rule
        System.out.println("check rule");
    }
}
import com.mayikt.projecttest.responsibilitychain.AbstractHandler;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *  安全校验对象
 */
@Component
@Order(2) //校验顺序排第2
public class CheckSecurityFilterObject extends AbstractHandler {

    @Override
    public void doFilter(HttpServletRequest request, HttpServletResponse response) {
        //invoke Security check
        System.out.println("安全调用校验");
    }
}

3.3 对象链连起来(初始化)&& 使用

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

@Component("ChainPatternDemo")
public class ChainPatternDemo {

    //自动注入各个责任链的对象
    @Autowired
    private List<AbstractHandler> abstractHandleList;

    private AbstractHandler abstractHandler;

    //spring注入后自动执行,责任链的对象连接起来
    @PostConstruct
    public void initializeChainFilter(){

        for(int i = 0;i<abstractHandleList.size();i++){
            if(i == 0){
                abstractHandler = abstractHandleList.get(0);
            }else{
                AbstractHandler currentHander = abstractHandleList.get(i - 1);
                AbstractHandler nextHander = abstractHandleList.get(i);
                currentHander.setNextHandler(nextHander);
            }
        }
    }

    //直接调用这个方法使用
    public void exec(HttpServletRequest request, HttpServletResponse response) {
        abstractHandler.filter(request, response);

    }

    public AbstractHandler getAbstractHandler() {
        return abstractHandler;
    }

    public void setAbstractHandler(AbstractHandler abstractHandler) {
        this.abstractHandler = abstractHandler;
    }
}

3.4 责任链案例

Api接口限流→黑名单拦截→用户会话→参数过滤

3.4.1 GatewayHandler抽象角色
public abstract class GatewayHandler {
    protected GatewayHandler nextGatewayHandler;

    /**
     * 处理业务逻辑
     *
     * @return true 表示继续执行 false表示不继续执行..
     */
    public abstract void service();

    public void setHandler(GatewayHandler gatewayHandler) {
        this.nextGatewayHandler = gatewayHandler;
    }
    protected void nextService(){
         if(nextGatewayHandler!=null){
             nextGatewayHandler.service();;
         }
    }
}
3.4.2 具体Handler实现
@Component
public class CurrentLimitHandler extends GatewayHandler {
    @Override
    public void service() {
        System.out.println("第一关网关限流判断....");
        nextService();
    }
}
@Component
public class ConversationHandler extends GatewayHandler {
    @Override
    public void service() {
        System.out.println("第三关用户会话拦截判断....");
        nextService();
    }
}
@Component
public class BlacklistHandler extends GatewayHandler {
    @Override
    public void service() {
        System.out.println("第二关黑名单拦截判断....");
        nextService();
    }
}
@Component
public class ConversationHandler extends GatewayHandler {
    @Override
    public void service() {
        System.out.println("第三关用户会话拦截判断....");
        nextService();
    }
}
3.4.3 构建链上关系
public class FactoryHandler {
    public static GatewayHandler getGatewayHandler() {
        GatewayHandler gatewayHandler1 = new CurrentLimitHandler();
        GatewayHandler gatewayHandler2 = new BlacklistHandler();
        gatewayHandler1.setHandler(gatewayHandler2);
        GatewayHandler gatewayHandler3 = new ConversationHandler();
        gatewayHandler2.setHandler(gatewayHandler3);
        return gatewayHandler1;
    }
}

4.代理模式

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * jdk动态代理
 *
 * @author zx
 * @date 2022年01月16日 11:38
 */
public class JdkDynamicProxy<T> implements InvocationHandler {

    private T target;

    public JdkDynamicProxy(T target) {
        this.target = target;
    }

    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行目标方法之前");
        Object invoke = method.invoke(target, args);
        System.out.println("执行目标方法之后");
        return invoke;
    }
}
/**
 * @author zx
 * @date 2022年01月16日 11:43
 */
public interface UserService {
    String getUserInfo();
}


import com.mayikt.springsource.service.UserService;

/**
 * @author zx
 * @date 2022年01月16日 11:44
 */
public class UserServiceImpl implements UserService {
    @Override
    public String getUserInfo() {
        return "tom is java paramgrame";
    }
}
import com.mayikt.springsource.service.UserService;
import com.mayikt.springsource.config.MyConfig;
import com.mayikt.springsource.service.imple.UserServiceImpl;
import com.mayikt.springsource.proxy.JdkDynamicProxy;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author zx
 * @date 2022年01月16日 9:33
 */
public class MainTest {
    public static void main(String[] args) {
     
        JdkDynamicProxy<UserService> userServiceJdkDynamicProxy = new JdkDynamicProxy<>(new UserServiceImpl());
        UserService proxy = userServiceJdkDynamicProxy.getProxy();
        String userInfo = proxy.getUserInfo();
        System.out.println(userInfo);
    }

}

4.1 JDK代理的另一种写法

多个接口实现代理

package com.mayikt.designpattern.structurepattern.jdkproxy;

public  interface ManTikTok {
   void tiktok();
}
package com.mayikt.designpattern.structurepattern.jdkproxy;

public interface SellTikTok {

    void sell();
}
package com.mayikt.designpattern.structurepattern.jdkproxy;

//
public class LeiTikTok  implements ManTikTok,SellTikTok {
//    @Override
    public void tiktok() {
        System.out.println("雷丰阳,tiktok.... ");
    }

    @Override
    public void sell() {
        System.out.println("雷丰阳,只要666,赶紧来包...");
    }

    public void haha(){
        System.out.println("hahaha ,......");
    }
}
public class JdkProxy {
    /**
     * 被代理类 ,即目标类
     * 目标类需要实现公共的接口
     */
    private Object target;

    public JdkProxy(Object target) {
        this.target = target;
    }

    /**
     * 获取代理对象
     */
    public <T> T getProxyObj() {
        InvocationHandler handler = (proxy, method, args) -> {
            System.out.println("1.方法前执行~~~~~");
            Object invoke = method.invoke(target, args);
            if (invoke != null) {
                System.out.println(invoke);
            }
            System.out.println("2.方法后执行~~~~~~");
            return invoke;
        };
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), handler);
    }
}
public class MainTestProxy {
    public static void main(String[] args) {

        ManTikTok proxyObj = new JdkProxy(new LeiTikTok()).getProxyObj();
        proxyObj.tiktok();

    }
}

4.2 实现Mapper代理-lambda写法

import com.example.proxy.anotaion.Select;

public interface IUserDao {
 @Select("select * from mayikt_type where id = #{uId}")
 String queryUserInfo(String uId);
}
import com.example.proxy.anotaion.Select;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 对代理类的定义
 * @param <T>
 */
public class MapperFactoryBean<T> implements FactoryBean<T> {
    private Logger logger =  LoggerFactory.getLogger(MapperFactoryBean.class);
    private Class<T> mapperInterface;

    public MapperFactoryBean(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    @Override
    public T getObject() throws Exception {
        InvocationHandler handler = (proxy, method, args) -> {
            Select select = method.getAnnotation(Select.class);
            logger.info("SQL:{}", select.value().replace("#{uId}", args[0].toString()));
            return args[0] + ",沉淀、分享、成⻓,让⾃⼰和他 ⼈都能有所收获!";
        };
        return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]
                        {mapperInterface}, handler);
    }

    @Override
    public Class<?> getObjectType() {
        return mapperInterface;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
import com.example.proxy.mapper.IUserDao;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;

/**
 * 这⾥我们将代理的bean交给spring容器管理,也就可以⾮常⽅便让我们可以获取到代理的bean。这部分是spring中关于⼀个bean注册过程的源码。
 * GenericBeanDefinition ,⽤于定义⼀个bean的基本信息 setBeanClass(MapperFactoryBean.class);
 * ,    也包括可以透传给构造函数信息 addGenericArgumentValue(IUserDao.class);
 * 最后使⽤ BeanDefinitionReaderUtils.registerBeanDefinition ,进⾏bean的注册,也就
 * 是注册到 DefaultListableBeanFactory 中。
 */
public class RegisterBeanFactory implements BeanDefinitionRegistryPostProcessor/*beanfactory后置处理器*/ {

    /**
     * 注册bean定义信息注入到容器中
     * @param registry
     * @throws BeansException
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(MapperFactoryBean.class);
        beanDefinition.setScope("singleton");

        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(IUserDao.class);
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, "userDao");
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
       default-autowire="byName">
    <bean id="userDao"
          class=" com.example.proxy.factory.RegisterBeanFactory"/>
</beans>
@SpringBootTest

class MayiktProxyDemoApplicationTests {
    Logger logger = LoggerFactory.getLogger(MayiktProxyDemoApplicationTests.class);


    @Test
    void contextLoads() {
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config.xml");
        IUserDao userDao = beanFactory.getBean("userDao", IUserDao.class);
        String res = userDao.queryUserInfo("1");
        logger.info("测试结果:{}", res);
    }

}

SpringAop 中使用jdk代理和cglib代理, 被代理类实现抽象主题接口实现接口 采用的是jdk代理; 被代理类继承抽象的主题角色采用cglib代理

4.3 对接口方法代理

在一些rpc框架中,客户端只需要关注接口的的调用,而具体的远程请求则由框架内部实现。

public interface OrderInterface {
   /**
    * 生成一张新订单
    */
   void addOrder(String name);
}
import com.example.proxy.util.HttpClientUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class SimpleRpcFrame {

    Logger logger = LoggerFactory.getLogger(SimpleRpcFrame.class);

    /**
     * 创建一个远程请求代理对象
     */
    public static <T> T getRemoteProxy(Class<T> service) {
        return (T) Proxy.newProxyInstance(service.getClassLoader(),
                new Class<?>[]{service},
                new RpcHandler(service));
    }

    /**
     * 处理具体远程调用的类
     */
    static class RpcHandler implements InvocationHandler {
        Logger logger = LoggerFactory.getLogger(RpcHandler.class);
        private Class service;

        public RpcHandler(Class service) {
            this.service = service;
        }

        //真正调用远程接口
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            /**
             * 根据接口名和方法名,发起一次特定的网络请求,获取数据
             */
            //Object result = RemoteCallUtility.request(service.getName(), method.getName(), args);
            String name = service.getName();
            String name1 = method.getName();

            Object result = null;
            //logger.info("参数args:{}",args);
            //
            //JSONArray jsonArray = JSON.parseArray(args.toString());
            //logger.info("转换后的jsonArray:{}",jsonArray);
            result = HttpClientUtil.doPost("http://www.baidu.com", null);
            return result;
        }
    }
}
public class RpcInvoker {
    public void invoke(String name) {
        OrderInterface order = SimpleRpcFrame.getRemoteProxy(OrderInterface.class);
        order.addOrder(name);
    }
}
  @Test
    void proxyInterface(){
        RpcInvoker rpcInvoker = new RpcInvoker();
        rpcInvoker.invoke("zhongxu");

    }

二、@EnableAspectJAutoProxy源码分析

2.1 创建代理对象

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 */
	boolean proxyTargetClass() default false;

	/**
	 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
	 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
	 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
	 * @since 4.3.1
	 */
	boolean exposeProxy() default false;

}

根据给定的EnableAspectJAutoProxy注解,根据当前的BeanDefinitionRegistry注册AnnotationAwareAspectJAutoProxyCreator

AbstractAutoProxyCreator 的后置通知中创建代理类. 最终实现BeanPostProcessor后置处理,Bean初始化之后调用,最终放到一级缓存中。[结合Bean创建生命周期,没有循环依赖,在初始化之后会调用后置处理器]

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

wrapIfNecessary(bean, beanName, cacheKey); 如有必要,包装给定的bean,即如果它有资格被代理

Necessary 必要的

wrap 包

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

通过代理工厂创建代理对象.其中封装了切面调用链路封装Advisor

	protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (proxyFactory.isProxyTargetClass()) {
			// Explicit handling of JDK proxy targets (for introduction advice scenarios)
			if (Proxy.isProxyClass(beanClass)) {
				// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
				for (Class<?> ifc : beanClass.getInterfaces()) {
					proxyFactory.addInterface(ifc);
				}
			}
		}
		else {
			// No proxyTargetClass flag enforced, let's apply our default checks...
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		// Use original ClassLoader if bean class not locally loaded in overriding class loader
		ClassLoader classLoader = getProxyClassLoader();
		if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
			classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
		}
		return proxyFactory.getProxy(classLoader);
	}

DefaultAopProxyFactory.createAopProxy() 创建代理对象

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (!NativeDetector.inNativeImage() &&
				(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

2.2 如何判断类实现接口

DefaultAopProxyFactory.createAopProxy() 创建代理对象 中的判断类是否实现接口hasNoUserSuppliedProxyInterfaces(config))

确定提供的AdvisedSupport是否仅指定了SpringProxy接口(或根本没有指定代理接口)

/**
	 * Determine whether the supplied {@link AdvisedSupport} has only the
	 * {@link org.springframework.aop.SpringProxy} interface specified
	 * (or no proxy interfaces specified at all).
	 */
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
    Class<?>[] ifcs = config.getProxiedInterfaces();
    return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}

三、AOP底层调用链路分析

递归责任链调用方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值