@EnableXXX在spring项目中很常见,下面看看它背后的原理,其实它的实现离不开spring bean的生命周期。
1、定义@MyFeginClientScanner注解,修饰接口,表示接口使用动态代理生成实例。
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFeginClientScanner {
String url() default "";
}
2、定义@MyFeginClientRequestMapping注解,修饰方法。
@Target(ElementType.METHOD)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFeginClientRequestMapping {
String value() default "";
}
3、定义@EnableMyFeginClientAutoConfiguration注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(MyFeginClientAutofigurationRegistrar.class)
public @interface EnableMyFeginClientAutoConfiguration {
String basePackage() default "";
//设置代理类实现,默认为使用JDK动态代理
Class<? extends AbstractMyFeginClientFactoryBean> implClass() default MyFeginClientFactoryBean.class;
}
4、创建MyFeginClientAutofigurationRegistrar和MyFeginClientClasspathScanner这两个主要功能是扫描basePackage包下 @MyFeginClientScanner注解的类解析为BeanDefinition。
public class MyFeginClientClasspathScanner extends ClassPathBeanDefinitionScanner {
private static final Logger logger = LoggerFactory.getLogger(MyFeginClientClasspathScanner.class);
private Class<? extends AbstractFactoryBean> factoryBeanImplClass;
public MyFeginClientClasspathScanner(BeanDefinitionRegistry registry) {
super(registry);
}
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
//BeanDefinitionHolder 封装了BeanDefinition,beanName以及aliases
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
logger.info("find beanDefinitions :" + beanDefinitions);
if (!beanDefinitions.isEmpty()) {
for (BeanDefinitionHolder holder : beanDefinitions) {
GenericBeanDefinition defination = (GenericBeanDefinition) holder.getBeanDefinition();
defination.getPropertyValues().addPropertyValue("mapperInterface", defination.getBeanClassName());
// 设置bean工厂和对应的属性值
defination.setBeanClass(this.factoryBeanImplClass);
defination.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
return beanDefinitions;
}
/**
* {@inheritDoc}
*/
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return (beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent());
}
/**
* {@inheritDoc}
*/
@Override
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (super.checkCandidate(beanName, beanDefinition)) {
return true;
} else {
logger.warn("Skipping MapperFactoryBean with name '" + beanName + "' and '" + beanDefinition.getBeanClassName() + "' mapperInterface"
+ ". Bean already defined with the same name!");
return false;
}
}
public void setFactoryBeanImplClass(Class<? extends AbstractFactoryBean> factoryBeanImplClass) {
this.factoryBeanImplClass = factoryBeanImplClass;
}
}
public class MyFeginClientAutofigurationRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
private static final Logger logger = LoggerFactory.getLogger(MyFeginClientAutofigurationRegistrar.class);
private Environment env;
private ResourceLoader resourceLoader;
@Override
public void setEnvironment(Environment environment) {
this.env = environment;
if (logger.isDebugEnabled()) {
logger.debug("setEnvironment");
}
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
if (logger.isDebugEnabled()) {
logger.debug("setResourceLoader");
}
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (logger.isDebugEnabled()) {
logger.debug("registerBeanDefinitions");
}
// 获取MyFeginClientScanner配置的basePackage
AnnotationAttributes annoAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(EnableMyFeginClientAutoConfiguration.class.getName()));
String basePackage = annoAttrs.getString("basePackage");
//使用implClass来切换代理实现方式
//@EnableMyFeginClientAutoConfiguration(basePackage = "com.luna.springbootpractice.demo.service",implClass = MyFeginClientCgLibFactoryBean.class)
Class<? extends AbstractFactoryBean> implClass = annoAttrs.getClass("implClass");
// 扫描带有MyFeginClientScanner注解的接口
MyFeginClientClasspathScanner scanner = new MyFeginClientClasspathScanner(registry);
scanner.setResourceLoader(resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(MyFeginClientScanner.class));
scanner.setFactoryBeanImplClass(implClass);
scanner.doScan(basePackage);
}
}
5、创建MyFeginClientSupport接口,接口DefaultMyFeginClientSupport,在这里可以处理请求。
public interface MyFeginClientSupport {
Object invoke(Object proxy, Method method, Object[] args);
}
public class DefaultMyFeginClientSupport implements MyFeginClientSupport {
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
MyFeginClientScanner myFeginClientScanner = method.getDeclaringClass().getAnnotation(MyFeginClientScanner.class);
MyFeginClientRequestMapping myFeginClientRequestMapping = method.getAnnotation(MyFeginClientRequestMapping.class);
if (myFeginClientRequestMapping == null) {
return null;
}
String value = myFeginClientRequestMapping.value();
String url = StringUtils.join(myFeginClientScanner.url(), value);
String result = null;
if (args != null && args.length == 1) {
//发送http请求
//Map<String,Object> params = new HashMap<String, Object>(1);
//params.put("param",args[0]);
//JSONObject jsonObject = HttpClientPoolUtil.doGet(url,params);
JSONObject jsonObject = new JSONObject();
jsonObject.put("test", args[0]);
result = jsonObject.toJSONString();
}
if (method.getReturnType() == String.class) {
return result;
}
return null;
}
}
6、创建动态代理的InvocationHandler实现类。
public class MyFeginClientInvocationHandler implements InvocationHandler {
private MyFeginClientSupport myFeginClientSupport;
public MyFeginClientInvocationHandler(MyFeginClientSupport myFeginClientSupport) {
this.myFeginClientSupport = myFeginClientSupport;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return myFeginClientSupport.invoke(proxy,method, args);
}
}
7、实现FactoryBean,先定义AbstractMyFeginClientFactoryBean然后再利用JDK动态代理和CGLIB代理生成实现类。
public class AbstractMyFeginClientFactoryBean<T> implements FactoryBean<T>, InitializingBean {
@Autowired
private MyFeginClientSupport myFeginClientSupport;
private Class<?> mapperInterface;
private T t;
public void setProxyTarget(T t) {
setT(t);
}
@Override
public T getObject() throws Exception {
return t;
}
@Override
public Class getObjectType() {
return mapperInterface;
}
@Override
public void afterPropertiesSet() throws Exception {
}
public MyFeginClientSupport getMyFeginClientSupport() {
return myFeginClientSupport;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public Class<?> getMapperInterface() {
return mapperInterface;
}
public void setMapperInterface(Class<?> mapperInterface) {
this.mapperInterface = mapperInterface;
}
}
JDK动态代理FactoryBean:
public class MyFeginClientFactoryBean<T> extends AbstractMyFeginClientFactoryBean<T> {
@SuppressWarnings("unchecked")
@Override
public void afterPropertiesSet() throws Exception {
T target = (T) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { getMapperInterface() },
new MyFeginClientInvocationHandler(getMyFeginClientSupport()) );
setProxyTarget(target);
}
}
CGLIB代理FactoryBean:
public class MyFeginClientCgLibFactoryBean<T> extends AbstractMyFeginClientFactoryBean<T> implements MethodInterceptor {
@SuppressWarnings("unchecked")
@Override
public void afterPropertiesSet() throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setCallback(this);
enhancer.setSuperclass(getMapperInterface());
setProxyTarget((T) enhancer.create());
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
return getMyFeginClientSupport().invoke(obj,method, args);
}
}
8、创建测试service。
@MyFeginClientScanner(url = "http://localhost:80")
public interface TestMyFeginClientService {
@MyFeginClientRequestMapping(value = "/test")
public String test(String param);
}
9、运行测试类。
public class TestMyFeginClientServiceTest extends SpringbootpracticeApplicationTests {
@Autowired
private TestMyFeginClientService testMyFeginClientService;
@Test
public void test() {
String result = testMyFeginClientService.test("test");
System.out.println(result);
}
}
输出:{"test":"test"}