將創建的動態代理對象注入到 Spring 容器中(仿AOP)

系統服務類

系統接口

public interface ISystemService {
    int saveRecord();
}

系統實現類

@Slf4j
@Service
// 標識該類爲動態代理類
@Proxy(interceptor = MyInterceptor.class)
public class SystemServiceImpl implements ISystemService {
    @Autowired
    private RoleService roleService;

    @Override
    public int saveRecord() {
        log.info("saveRecord execute...");

        roleService.saveRole();
        return 0;
    }
}

角色服務類

@Slf4j
@Service
public class RoleService {
    public void saveRole() {
        log.info("保存角色信息");

    }
}

控制層

@Slf4j
@RestController
@RequestMapping(value = "/system", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class SystemController {
    @Autowired
    private ISystemService systemService;
    
    @RequestMapping("/save")
    public Response save() {
        systemService.saveRecord();
        
        return Response.success();
    } 
}

 

注入自定義 bean 配置類

@Slf4j
@Configuration
public class CustomizeScannerConfigurer implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
    public static final String BASE_PACKAGES = "com.jaemon.oms";

    /**
     * 註冊自定義 bean 到 Spring 容器中
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        List<Class<?>> classNames = Lists.newArrayList();
        PackageUtils.classNames(BASE_PACKAGES, classNames);

        for (Class<?> className : classNames) {
            Proxy proxy = className.getAnnotation(Proxy.class);
            String beanName = proxy.value();
            Class<?> interceptor = proxy.interceptor();

            if ("".equals(beanName)) {
                String shortClassName = ClassUtils.getShortName(className.getName());
                beanName = Introspector.decapitalize(shortClassName);
            }

            // 被代理對象, 即: 實際對象
            Object actualBean = getBean(className);

            // 爲被代理對象中依賴的屬性注入值
            Field[] actualBeanFields = actualBean.getClass().getDeclaredFields();
            for (Field actualBeanField : actualBeanFields) {
                if (actualBeanField.getModifiers() == Modifier.PRIVATE) {
                    actualBeanField.setAccessible(true);
                    try {
                        actualBeanField.set(actualBean, getBean(actualBeanField.getType()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }

            // 代理對象操作的攔截器
            Object interceptorBean = null;
            try {
//                actualBean = className.newInstance();
                interceptorBean = interceptor.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }

            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(className);
            GenericBeanDefinition definition = (GenericBeanDefinition) beanDefinitionBuilder.getRawBeanDefinition();
            definition.setBeanClass(ProxyFactoryBean.class);
            // 設置屬性值
            definition.getPropertyValues().add("target", actualBean);
            definition.getPropertyValues().add("interfaces", className.getInterfaces());
            definition.getPropertyValues().add("interceptor", interceptorBean);
            // 設置可通過 @Autowired 註解訪問
            definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
            // 註冊到 BeanDefinitionRegistry
            registry.registerBeanDefinition(beanName, definition);
        }
    }

    /**
     * 對bean定義做一些改變
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
        String[] beanDefinitionNames = factory.getBeanDefinitionNames();

        // 打印持有的bean的屬性情況
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition bd = factory.getBeanDefinition(beanDefinitionName);

            // TODO 可以對 bean 的定義做一些改變

            if (bd.getPropertyValues().size() > 0) {
                log.info("bean[{}] bean properties[{}]", beanDefinitionName, bd.getPropertyValues().size());
            }
        }
    }

    /**
     * 注入普通 bean 到 Spring 容器
     */
    private void ordinaryBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        List<Class<?>> classNames = Lists.newArrayList();
        PackageUtils.classNames(BASE_PACKAGES, classNames);

        for (Class<?> className : classNames) {
            // 創建一個bean的定義類的對象
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(className);

            // 將 Bean 的定義註冊到 Spring 容器中
            registry.registerBeanDefinition(className.getSimpleName(), rootBeanDefinition);
        }
    }

    public static <T> T getBean(Class<T> clazz){
        return context.getBean(clazz);
    }

    private static ApplicationContext context;

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

可參考: org.mybatis.spring.mapper.MapperScannerConfigurer

 

動態代理註解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Proxy {
    String value() default "";

    Class<? extends Interceptor> interceptor();
}

用於標識指定類爲動態代理類, interceptor 值爲切面操作類

 

動態代理相關類

代理bean生成工廠類

@Data
public class ProxyFactoryBean<T> implements FactoryBean<T> {
    private Class<T> interfaces;
    private Interceptor interceptor;
    private Object target;

    @Override
    public T getObject() throws Exception {
        return (T) Proxy.newProxyInstance(interfaces.getClassLoader(),
                new Class[]{interfaces}, new PluginProxy(target, interceptor));
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}

JDK 動態代理

@Slf4j
public class PluginProxy implements InvocationHandler {
    private final Object target;
    private final Interceptor interceptor;

    public PluginProxy(Object target, Interceptor interceptor) {
        this.target = target;
        this.interceptor = interceptor;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        try {
            // 前置業務處理
            log.info("method[{}] 前置處理", method.getName());
            interceptor.preHandle();

            Object result = method.invoke(target, args);

            // 後置業務處理
            log.info("method[{}] 後置處理", method.getName());
            interceptor.afterHandle();

            return result;
        } catch (Exception e) {
            return interceptor.catchException(e);
        } finally {
            interceptor.doAfterCompleted();
        }
    }

}

 

攔截相關類

攔截接口

public interface Interceptor {

    /**
     * 執行被代理方法前執行
     */
    void preHandle();

    /**
     * 執行被代理方法後執行
     */
    void afterHandle();

    /**
     * 被代理方法執行異常時執行
     *
     * @param exception ex
     * @return rlt
     */
    Object catchException(Exception exception);

    /**
     * 代理方法執行結束時執行
     */
    void doAfterCompleted();
}

攔截實現類

@Slf4j
public class MyInterceptor implements Interceptor {
    @Override
    public void preHandle() {
        log.info("preHandle");
    }

    @Override
    public void afterHandle() {
        log.info("afterHandle");
    }

    @Override
    public Object catchException(Exception exception) {
        log.info("catchException異常啦。。。");
        return null;
    }

    @Override
    public void doAfterCompleted() {
        log.info("doAfterCompleted");
    }
}

 

工具類

public class PackageUtils {
    public static final String SPOT = ".";
    public static final String SLANT = "/";

    private PackageUtils() {}

    /**
     * 獲取指定包下所有的類
     *
     * @param packageName
     * @param classNames
     */
    public static void classNames(String packageName, List<Class<?>> classNames) {
       try {
           ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
           URL url = classLoader.getResource(packageName.replace(SPOT, SLANT));
           URI uri = url.toURI();
           File file = new File(uri);
           File[] files = file.listFiles();

           for (File f : files) {
               String name = f.getName();

               if (f.isFile()) {
                   String className = packageName + SPOT + name.substring(0, name.lastIndexOf(SPOT));
                   Class<?> clazz = Class.forName(className);
                   if (clazz.isAnnotationPresent(Proxy.class)) {
                       classNames.add(clazz);
                   }
               } else {
                   classNames(packageName + SPOT + name, classNames);
               }
           }
       } catch (Exception e) {
           e.printStackTrace();
       }
    }


    public static void main(String[] args) throws Exception {
        List<Class<?>> classNames = Lists.newArrayList();
        classNames("com.jaemon.bigdata", classNames);

        classNames.forEach(e -> System.out.println(e.getName()));

        System.out.println(classNames.size());
    }

}

 

Reference

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章