系統服務類
系統接口
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());
}
}