zoukankan      html  css  js  c++  java
  • Spring源码分析之AOP

    一、AOP的原理

      动态代理

    二、例子

    public interface UserService {
    
        int addUser(User user);
    
        List<User> getUsers(@Param("hobby") String hobby);
    }
    @Service
    public class UserServiceImpl implements UserService {
    
        @Autowired
        private UserDao userDao;
    
        @Override
        public int addUser(User user) {
            return userDao.addUser(user);
        }
    
        @Override
        public List<User> getUsers(String hobby) {
            return userDao.getUsers(hobby);
        }
    }
    @Aspect
    @Component
    public class AopTest {
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        ThreadLocal<Long> startTime = new ThreadLocal<>();
    
        @Pointcut("execution(public * com.tpl.system.service..*.*(..))")
        public void pointcut() {
    
        }
    
        @Before("pointcut()")
        public void doBefore(JoinPoint joinPoint) throws Exception {
            logger.info("RequestParam:{}", Arrays.toString(joinPoint.getArgs()));
        }
    
        @AfterReturning(returning = "response", pointcut = "pointcut()")
        public void doAfterRunning(Object response) {
            //打印返回值信息
            logger.info("Response:[{}]", response);
            //打印请求耗时
        }
    }

    三、源码

        /**
         * Create a proxy with the configured interceptors if the bean is
         * identified as one to proxy by the subclass.
         * @see #getAdvicesAndAdvisorsForBean
         */
        @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;
        }

    如有必要进行包装

    /**
         * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
         * @param bean the raw bean instance
         * @param beanName the name of the bean
         * @param cacheKey the cache key for metadata access
         * @return a proxy wrapping the bean, or the raw bean instance as-is
         */
        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;
        }

    创建代理

    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()) {
                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);
            }
    
            return proxyFactory.getProxy(getProxyClassLoader());
        }
    public Object getProxy(@Nullable ClassLoader classLoader) {
            return createAopProxy().getProxy(classLoader);
        }

    获取AopProxy,可能是JdkDynamicAopProxy或者ObjenesisCglibAopProxy

    1、如果被代理的目标类实现了一个或多个自定义的接口,返回JdkDynamicAopProxy

    2、如果没有实现任何接口,会使用 CGLIB 实现代理

    3、如果设置了 proxy-target-class="true",那么都会使用 CGLIB。

        @Override
        public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            if (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);
            }
        }

    接下去就是JDK 和CGLib分别实现自己的逻辑了,JDK 动态代理基于接口,所以只有接口中的方法会被增强,而 CGLIB 基于类继承,需要注意就是如果方法使用了 final 修饰,或者是 private 方法,是不能被增强的

  • 相关阅读:
    PHP安全编程:更优的会话数据安全 更好地防范session暴露(转)
    PHP安全编程:会话数据注入 比会话劫持更强大的攻击(转)
    小菜学习设计模式(四)—原型(Prototype)模式
    小菜学习设计模式(三)—工厂方法(Factory Method)模式
    从头学习设计模式(一)——单例模式
    javascript Date format(js日期格式化)
    您尝试打开的文件的格式与文件扩展名指定的格式不一致
    C# foreach 中获取索引index的方法
    C# DateTime日期格式化
    oracle的常用函数 instr() 和substr()函数
  • 原文地址:https://www.cnblogs.com/TripL/p/13266786.html
Copyright © 2011-2022 走看看