Spring扩展
为什么要扩展
做java开发Spring是必须要用的而且用的很频繁。
Spring的核心IOC和AOP是我们最想要的,但是有些时候需要把我们自定义的bean的生产过程,bean创建好之后再交给Spring容器。所以重点来了怎么交给它
其实Spring的设计早就考虑到这些问题了,只是平时没怎么使用而已,本文带你解开它神秘的面纱。
理论加实践
1.使用Component注解
想让Spring扫描我们自定义的注解很简单。只需要在我们的注解上加上 @org.springframework.stereotype.Component 代码如下:
1 2 3 4 5 6 @Component @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MyService { String value() default "";// 必须要有 }
以上就可以让Spring扫描到我们的注解,作用和Spring的注解作用是一样的。 细心的同学可能已经发现 org.springframework.stereotype.Controller 的注解不就是这样实现的嘛。 让我们来看看这是为什么,在 org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider类中的registerDefaultFilters 方法中有 this.includeFilters.add(new AnnotationTypeFilter(Component.class))这样一句话,看到这里明白了吧 。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @SuppressWarnings("unchecked") protected void registerDefaultFilters() { this.includeFilters.add(new AnnotationTypeFilter(Component.class)); ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader(); try { this.includeFilters.add(new AnnotationTypeFilter( ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false)); logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning"); } catch (ClassNotFoundException ex) { // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip. } try { this.includeFilters.add(new AnnotationTypeFilter( ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false)); logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. } }
你以为这样就完了嘛?如果仅仅是装个x确实完了,被他注解的类会被Spring管理。 但是对于我们来讲是不够滴,应为我们还要定义这个bean的生产过程呀!这才是真正的目的。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 @Component public class MyBeanPostProcessor implements BeanPostProcessor { public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization "+ beanName); return bean; } public Object postProcessBeforeInitialization(``````Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization "+ beanName); return bean; } }
BeanPostProcessor接口作用是:如果我们需要在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。两个方法一个之前 一个之后。注册到容器时两个方法都会调,获取的时会调postProcessBeforeInitialization方法。我们可以在这里把bean在定制一番,怎么定制就看个人需求啦不再讲述。听SpringMvc就是采用的这种策略,没去验证过。第一种方法就介绍完了。
2.扫描包解析注解
先定义注解代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 import java.lang.annotation.Documented; 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) @Documented public @interface Component { String value() default ""; }
扫描 既然用到了Spring那么就让Spring来帮我们扫描代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.Set; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.core.type.filter.AnnotationTypeFilter; public final class Scanner extends ClassPathBeanDefinitionScanner { public Scanner(BeanDefinitionRegistry registry) { super(registry); } public void registerDefaultFilters() { this.addIncludeFilter(new AnnotationTypeFilter(Component.class)); } public Set<BeanDefinitionHolder> doScan(String... basePackages) { //super.doScan(basePackages) 会把生成的bean 加入Spring容器 Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); for (BeanDefinitionHolder holder : beanDefinitions) { GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition(); // beanClassName给FactoryBeanImpl使用,还以再加几个Property definition.getPropertyValues().add("beanClassName", definition.getBeanClassName()); definition.setBeanClass(FactoryBeanImpl.class); } return beanDefinitions; } public boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { return super.isCandidateComponent(beanDefinition) && (beanDefinition.getMetadata().hasAnnotation(Component.class.getName())); } }
上面的代码就是扫描,解析后得到的BeanDefinitionHolder 然后指定工厂FactoryBeanImpl生产后加入容器 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.cglib.core.SpringNamingPolicy; import org.springframework.cglib.proxy.Enhancer; public class FactoryBeanImpl<T> implements InitializingBean, FactoryBean<T> { private String beanClassName; public void setBeanClassName(String beanClassName) { this.beanClassName = beanClassName; } public T getObject() throws Exception { Class innerClass = Class.forName(beanClassName); if (innerClass.isInterface()) {//接口使用 jdk代理 return (T) InvocationHandlerImpl.newInstance(innerClass); } else {//类使用 cglib代理 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(innerClass); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setCallback(new MethodInterceptorImpl()); return (T) enhancer.create(); } } public Class<?> getObjectType() { try { return Class.forName(beanClassName); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } public boolean isSingleton() { return true; } public void afterPropertiesSet() throws Exception { } }
这个属性beanClassName是上面扫描绑定过来的。这里就是生成bean的工厂。getObject是bean的生成方法,代理就略过。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class InvocationHandlerImpl implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("ObjectProxy execute:" + method.getName()); return method.invoke(proxy, args); } public static <T> T newInstance(Class<T> innerInterface) { ClassLoader classLoader = innerInterface.getClassLoader(); Class[] interfaces = new Class[] { innerInterface }; InvocationHandlerImpl proxy = new InvocationHandlerImpl(); return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy); } } import java.lang.reflect.Method; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; public class MethodInterceptorImpl implements MethodInterceptor { public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("MethodInterceptorImpl:" + method.getName()); return methodProxy.invokeSuper(o, objects); } }
3.什么都做了,什么时候扫描
1 2 3 public Scanner(BeanDefinitionRegistry registry) { super(registry); }
在实例化Scanner时需要 BeanDefinitionRegistry该类的作用主要是向注册表中注册 BeanDefinition实例 完成注册的过程。 BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。 ConfigurableListableBeanFactory该类提供解析,修改bean定义,并与初始化单例. 在运行的时候传入的是 DefaultListableBeanFactory为 ConfigurableListableBeanFactory子类且实现了 BeanDefinitionRegistry 接口。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; public class BeanFactoryPostProcesserImpl implements BeanFactoryPostProcessor, ApplicationContextAware { private ApplicationContext applicationContext; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { Scanner scanner = new Scanner((BeanDefinitionRegistry) beanFactory);//可以强转 scanner.setResourceLoader(this.applicationContext); scanner.setBeanNameGenerator(new AnnotationBeanNameGenerator());//解析注解得到value值。 scanner.scan("com.extend.service");//可以在xml配置进来 不再演示 } } import java.beans.Introspector; import java.util.Map; import java.util.Set; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String COMPONENT_ANNOTATION_CLASSNAME = "com.extend.annotation2.Component"; @Override public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { if (definition instanceof AnnotatedBeanDefinition) { String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition); if (StringUtils.hasText(beanName)) { return beanName; } } return buildDefaultBeanName(definition, registry); } protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) { AnnotationMetadata amd = annotatedDef.getMetadata(); Set<String> types = amd.getAnnotationTypes(); String beanName = null; for (String type : types) { AnnotationAttributes attributes = AnnotationAttributes.fromMap(amd.getAnnotationAttributes(type, false)); // AnnotationAttributes attributes = // AnnotationConfigUtils.attributesFor(amd, type); if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) { Object value = attributes.get("value"); if (value instanceof String) { String strVal = (String) value; if (StringUtils.hasLength(strVal)) { if (beanName != null && !strVal.equals(beanName)) { throw new IllegalStateException("Stereotype annotations suggest inconsistent " + "component names: '" + beanName + "' versus '" + strVal + "'"); } beanName = strVal; } } } } return beanName; } protected boolean isStereotypeWithNameValue(String annotationType, Set<String> metaAnnotationTypes, Map<String, Object> attributes) { boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) || (metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) || annotationType.equals("javax.annotation.ManagedBean") || annotationType.equals("javax.inject.Named"); return (isStereotype && attributes != null && attributes.containsKey("value")); } protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { return buildDefaultBeanName(definition); } protected String buildDefaultBeanName(BeanDefinition definition) { String shortClassName = ClassUtils.getShortName(definition.getBeanClassName()); return Introspector.decapitalize(shortClassName); } }
以上就是实现过程 下面是测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import com.extend.annotation2.Component; @Component("disCaver1") public class TestService { public String getName() { System.err.println("hello world!"); return "hello world!"; } } public class Test { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-mybatis.xml"); context.start(); TestService disCaver1 = (TestService) context.getBean("disCaver1"); TestService disCaver2 = (TestService) context.getBean(TestService.class); disCaver1.getName(); context.close(); } }
spring-mybatis.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <bean class="com.extend.annotation2.BeanFactoryPostProcesserImpl"/> </beans>
结果: MethodInterceptorImpl:getName hello world!