系统服务类
系统接口
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());
}
}