栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

模仿 @Cacheable 实现自定义的 Cacheable 注解( 利用 BeanPostProcessor 和 cglib 对 spring 的 bean 进行二次代理 )

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

模仿 @Cacheable 实现自定义的 Cacheable 注解( 利用 BeanPostProcessor 和 cglib 对 spring 的 bean 进行二次代理 )

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableMyCache {
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCacheable {

    String cacheKey();
}
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class MyBeanPostProcessor implements ApplicationContextAware, BeanPostProcessor {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 获取 添加了 "EnableMyCache" 注解的 bean,然后 返回该 bean 的 cglib 代理对象
        EnableMyCache declaredAnnotation = bean.getClass().getDeclaredAnnotation(EnableMyCache.class);
        if( declaredAnnotation == null ){
            return bean;
        }

        MethodInterceptor methodInterceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                // 首先查询缓存中有没有,有直接返回,没有再调用目标方法获取结果返回
                MyCacheable annotation = method.getDeclaredAnnotation(MyCacheable .class);
                if( annotation == null ){
                    return methodProxy.invokeSuper(object, args);
                }
                String cacheKey = annotation.cacheKey();
                Object result = MyCache.get(cacheKey);
                if( result != null ){
                    return result;
                }
                result = methodProxy.invokeSuper(object, args);
                MyCache.put( cacheKey,result );
                return result;
            }
        };

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass( bean.getClass());
        enhancer.setCallback( methodInterceptor );
        Object beanPoxy = enhancer.create();
        BeanUtils.copyProperties( bean,beanPoxy );
        return beanPoxy;
    }
}

import org.springframework.stereotype.Component;

@Component
@EnableMyCache
@Getter
@Setter
public class TestService {

    @MyCacheable( cacheKey="xxxxxxxxxxxxxxx" )
    public Object get(){
        System.out.print( "模拟查询数据库...");
        return new Object();
    }
}
import com.alibaba.fastjson.JSONObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CommonTest {

    @Autowired
    private TestService testService;

    @Test
    public void test(){
        System.out.println( JSONObject.toJSonString( this.testService.get() ) );
        System.out.println( JSONObject.toJSonString( this.testService.get() ) );
        System.out.println( JSONObject.toJSonString( this.testService.get() ) );
        System.out.println( JSONObject.toJSonString( this.testService.get() ) );
    }

}

坑:

 1. TestService  得使用 @Getter、@Setter 注解,然后生成 TestService 的 cglib 代理对象后使用  BeanUtils.copyProperties( bean,beanPoxy ) ,否则 TestService 中的 @Autowired 注入不进来。

2. TestService 中的方法中供内部使用的 ,也就是使用 this.调用的方法必须是 public 的,否则 MethodInterceptor  不生效。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/324688.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号