自己实现的Spring父类注入

在开发过程如果使用全注解方式,难免会遇到一个类继承至某个父类,而这个父类的属性需要注入。

 

如果使用XML可以直接在XML配置文件中使用属性setter进行注入父类属性。

 

但是如果使用的是全注解,这个问题会比较棘手。

 

方法1:

自己在工程项目中写一个类继承至该父类A,而不要直接继承该父类A。原因是该父类A可能是另外的jar包中的类,该类A可能没有被annotation修饰,无法完成注入,而你自己写的继承至该类的子类B可以在项目中使用annotation进行属性注入(要复写父类的setter方法,然后使用annotation注解),然后项目中其它类C可以继承至类B,完成父类属性的注入

 

这种方法的可以解决父类注入的问题,但是要自己写一个父类实现一个中间的桥接。

 

方法2:

实现两级注入,所谓的两级注入即是首先依赖spring自身的注入逻辑完成子类主要属性的注入,而父类的某些属性注入依赖自己实现的BeanPostProcessor完成二级注入。

 

我目前实现的方法:

 

主要实现一个BeanPostProcessor:

Java代码   收藏代码
  1. import java.lang.reflect.Field;  
  2. import java.lang.reflect.Method;  
  3. import java.util.ArrayList;  
  4. import java.util.Arrays;  
  5. import java.util.HashSet;  
  6. import java.util.List;  
  7. import java.util.Set;  
  8.   
  9. import org.springframework.beans.BeansException;  
  10. import org.springframework.beans.factory.config.BeanPostProcessor;  
  11. import org.springframework.context.ApplicationContext;  
  12. import org.springframework.context.ApplicationContextAware;  
  13. import org.springframework.util.ReflectionUtils;  
  14.   
  15. public class InjectParentBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {  
  16.   
  17.     private ApplicationContext ctx;  
  18.   
  19.     private Set<String> alreadyInjected = new HashSet<String>();  
  20.   
  21.     private List<Class<?>> basicTypes = new ArrayList<Class<?>>() {  
  22.         private static final long serialVersionUID = 1L;  
  23.   
  24.         {  
  25.             add(char.class);  
  26.             add(Character.class);  
  27.             add(byte.class);  
  28.             add(Byte.class);  
  29.             add(short.class);  
  30.             add(Short.class);  
  31.             add(int.class);  
  32.             add(Integer.class);  
  33.             add(long.class);  
  34.             add(Long.class);  
  35.             add(String.class);  
  36.             add(float.class);  
  37.             add(Float.class);  
  38.             add(double.class);  
  39.             add(Double.class);  
  40.         }  
  41.     };  
  42.   
  43.     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
  44.         ParentInject injectParent = bean.getClass().getAnnotation(ParentInject.class);  
  45.         String[] aliases = ctx.getAliases(beanName);  
  46.         if (injectParent != null) {  
  47.             // 是否已经注入过  
  48.             Object hasInjected = hasInjected(bean, beanName, aliases);  
  49.             if (hasInjected != null) {  
  50.                 return hasInjected;  
  51.             }  
  52.   
  53.             return doInject(bean, beanName, aliases, injectParent);  
  54.         }  
  55.         return bean;  
  56.     }  
  57.   
  58.     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
  59.   
  60.         return bean;  
  61.     }  
  62.   
  63.     /** 
  64.      * 进行父类属性注入 
  65.      *  
  66.      * @param bean 
  67.      * @param beanName 
  68.      * @param injectParent 
  69.      * @return 
  70.      */  
  71.     private Object doInject(Object bean, String beanName, String[] aliases, ParentInject injectParent) {  
  72.         InjectItem[] items = injectParent.items();  
  73.         for (InjectItem item : items) {  
  74.             InjectStyle injectStyle = item.injectStyle();  
  75.             String attr = item.attr();  
  76.             String injectRef = item.ref();  
  77.             String injectValue = item.value();  
  78.   
  79.             Object injectObj = null;  
  80.             if (injectRef != null && !injectRef.trim().equals("")) {  
  81.                 injectObj = ctx.getBean(injectRef);  
  82.             }  
  83.   
  84.             if (injectObj == null) {  
  85.                 Field f = ReflectionUtils.findField(bean.getClass(), attr);  
  86.                 if (f == null) {  
  87.                     throw new RuntimeException("Class:" + bean.getClass() + " has not field:" + attr);  
  88.                 }  
  89.                 if (isBasicType(f.getType())) {  
  90.                     // 做基本类型转换  
  91.                     injectObj = basicTypeConvert(f.getType(), injectValue);  
  92.                 } else {  
  93.                     // 非基本类型,则猜测类型按类型注入  
  94.                     injectObj = ctx.getBean(f.getClass());  
  95.                 }  
  96.   
  97.             }  
  98.   
  99.             //注意如果是动态代理,属性注入会失败  
  100.             if (InjectStyle.ATTR_REFLECTION.equals(injectStyle)) {  
  101.                 // 按属性直接注入  
  102.   
  103.                 Field f = ReflectionUtils.findField(bean.getClass(), attr);  
  104.                 if (f == null) {  
  105.                     throw new RuntimeException("field does not exist:" + attr);  
  106.                 }  
  107.                 ReflectionUtils.makeAccessible(f);  
  108.                 ReflectionUtils.setField(f, bean, injectObj);  
  109.                 putInjected(aliases);  
  110.             } else if (InjectStyle.METHOD_INVOKE.equals(injectStyle)) {  
  111.                 // 按方法调用注入  
  112.   
  113.                 String injectMethod = item.injectMethod();  
  114.                 if (injectMethod == null || injectMethod.trim().equals("")) {  
  115.                     injectMethod = findSetterMethod(attr);  
  116.                 }  
  117.                 Method m = findInjectMethod(bean.getClass(), injectMethod, injectObj);  
  118.                 if (m == null) {  
  119.                     throw new RuntimeException("inject method does not exist:" + injectMethod);  
  120.                 }  
  121.                 ReflectionUtils.makeAccessible(m);  
  122.                 ReflectionUtils.invokeMethod(m, bean, injectObj);  
  123.                 putInjected(aliases);  
  124.             } else {  
  125.                 throw new RuntimeException("not supported injectStyle:" + injectStyle);  
  126.             }  
  127.   
  128.         }  
  129.         return bean;  
  130.     }  
  131.   
  132.     private Object basicTypeConvert(Class<?> class1, String injectValue) {  
  133.         if (byte.class.equals(class1) || Byte.class.equals(class1)) {  
  134.             return Byte.valueOf(injectValue);  
  135.         } else if (short.class.equals(class1) || Short.class.equals(class1)) {  
  136.             return Short.valueOf(injectValue);  
  137.         } else if (int.class.equals(class1) || Integer.class.equals(class1)) {  
  138.             return Integer.valueOf(injectValue);  
  139.         } else if (long.class.equals(class1) || Long.class.equals(class1)) {  
  140.             return Long.valueOf(injectValue);  
  141.         } else if (float.class.equals(class1) || Float.class.equals(class1)) {  
  142.             return Float.valueOf(injectValue);  
  143.         } else if (double.class.equals(class1) || Double.class.equals(class1)) {  
  144.             return Double.valueOf(injectValue);  
  145.         }  
  146.         return injectValue;  
  147.     }  
  148.   
  149.     /** 
  150.      * 是否是基本类型 
  151.      *  
  152.      * @param injectValue 
  153.      * @return 
  154.      */  
  155.     private boolean isBasicType(Class<?> cls) {  
  156.         return basicTypes.contains(cls);  
  157.     }  
  158.   
  159.     /** 
  160.      * 通过迭代找出当前类或者父类方法 
  161.      *  
  162.      * @param injectMethod 
  163.      * @return 
  164.      */  
  165.     private Method findInjectMethod(Class<?> cls, String injectMethod, Object... args) {  
  166.         Method[] methods = cls.getDeclaredMethods();  
  167.         for (Method method : methods) {  
  168.             if (method.getName().equals(injectMethod)) {  
  169.                 // 判断参数类型是否匹配  
  170.                 Class<?>[] paramTypes = method.getParameterTypes();  
  171.                 if (paramTypes.length == 1 && isSuitableBasicType(paramTypes[0], args[0].getClass())) {  
  172.                     return method;  
  173.                 }  
  174.   
  175.             }  
  176.         }  
  177.         List<Class<?>> parentClasses = new ArrayList<Class<?>>();  
  178.         if (cls.getSuperclass() != null) {  
  179.             parentClasses.add(cls.getSuperclass());  
  180.         }  
  181.   
  182.         parentClasses.addAll(Arrays.asList(cls.getInterfaces()));  
  183.         for (Class<?> c : parentClasses) {  
  184.             return findInjectMethod(c, injectMethod, args);  
  185.         }  
  186.         return null;  
  187.     }  
  188.   
  189.     private boolean isSuitableBasicType(Class<?> class1, Class<?> class2) {  
  190.         if (isByteTypeClass(class1) && isByteTypeClass(class2)) {  
  191.             return true;  
  192.         }  
  193.         if (isShortTypeClass(class1) && isShortTypeClass(class2)) {  
  194.             return true;  
  195.         }  
  196.         if (isIntTypeClass(class1) && isIntTypeClass(class2)) {  
  197.             return true;  
  198.         }  
  199.         if (isLongTypeClass(class1) && isLongTypeClass(class2)) {  
  200.             return true;  
  201.         }  
  202.         if (isFloatTypeClass(class1) && isFloatTypeClass(class2)) {  
  203.             return true;  
  204.         }  
  205.         if (isDoubleTypeClass(class1) && isDoubleTypeClass(class2)) {  
  206.             return true;  
  207.         }  
  208.         return class1.equals(class2);  
  209.     }  
  210.   
  211.     private boolean isByteTypeClass(Class<?> cls) {  
  212.         return byte.class.equals(cls) || Byte.class.equals(cls);  
  213.     }  
  214.   
  215.     private boolean isShortTypeClass(Class<?> cls) {  
  216.         return short.class.equals(cls) || Short.class.equals(cls);  
  217.     }  
  218.   
  219.     private boolean isIntTypeClass(Class<?> cls) {  
  220.         return int.class.equals(cls) || Integer.class.equals(cls);  
  221.     }  
  222.   
  223.     private boolean isLongTypeClass(Class<?> cls) {  
  224.         return long.class.equals(cls) || Long.class.equals(cls);  
  225.     }  
  226.   
  227.     private boolean isFloatTypeClass(Class<?> cls) {  
  228.         return float.class.equals(cls) || Float.class.equals(cls);  
  229.     }  
  230.   
  231.     private boolean isDoubleTypeClass(Class<?> cls) {  
  232.         return double.class.equals(cls) || Double.class.equals(cls);  
  233.     }  
  234.   
  235.     /** 
  236.      * 通过属性名找出setter方法 
  237.      *  
  238.      * @param attr 
  239.      * @return 
  240.      */  
  241.     private String findSetterMethod(String attr) {  
  242.         StringBuilder sb = new StringBuilder("set");  
  243.         sb.append(Character.toUpperCase(attr.charAt(0)));  
  244.         sb.append(attr.substring(1));  
  245.         return sb.toString();  
  246.     }  
  247.   
  248.     /** 
  249.      * 放置别名 
  250.      *  
  251.      * @param aliases 
  252.      */  
  253.     private void putInjected(String[] aliases) {  
  254.         alreadyInjected.addAll(Arrays.asList(aliases));  
  255.     }  
  256.   
  257.     /** 
  258.      * 判断是否已经注入 
  259.      *  
  260.      * @param bean 
  261.      * @param beanName 
  262.      * @return 
  263.      */  
  264.     private Object hasInjected(Object bean, String beanName, String[] aliases) {  
  265.   
  266.         for (String aliase : aliases) {  
  267.             if (alreadyInjected.contains(aliase)) {  
  268.                 return bean;  
  269.             }  
  270.         }  
  271.         return null;  
  272.     }  
  273.   
  274.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
  275.         ctx = applicationContext;  
  276.     }  
  277.   
  278. }  

 使用到了几个自定义注解:

ParentInject:

Java代码   收藏代码
  1. /** 
  2.  * 注入父类属性 
  3.  * 
  4.  */  
  5. @Retention(RetentionPolicy.RUNTIME)  
  6. @Target({ElementType.TYPE})  
  7. public @interface ParentInject {  
  8.       
  9.     /** 
  10.      * 注入项 
  11.      * @return 
  12.      */  
  13.     InjectItem[] items();  
  14.   
  15. }  

 InjectItem:

Java代码   收藏代码
  1. /** 
  2.  * 注意注入引用和注入值同时存在时,先判断引用是否存在,如果不存在,则注入值 
  3.  *  
  4.  * 
  5.  */  
  6. @Retention(RetentionPolicy.RUNTIME)  
  7. public @interface InjectItem {  
  8.     /** 
  9.      * 允许按类型注入,该情况出现在ref和value同时不存在的情况下,此时允许通过attr属性类型进行按类型注入 
  10.      * @return 
  11.      */  
  12.     boolean allowByType() default false;  
  13.       
  14.     /** 
  15.      * 属性名 
  16.      * @return 
  17.      */  
  18.     String attr() default "";  
  19.       
  20.     /** 
  21.      * 注入引用 
  22.      * @return 
  23.      */  
  24.     String ref() default "";  
  25.       
  26.     /** 
  27.      * 注入值 
  28.      * @return 
  29.      */  
  30.     String value() default "";  
  31.       
  32.     InjectStyle injectStyle() default InjectStyle.ATTR_REFLECTION;  
  33.       
  34.     /** 
  35.      * 注入方法 
  36.      * @return 
  37.      */  
  38.     String injectMethod() default "";  
  39.   
  40. }  

 InjectStyle

Java代码   收藏代码
  1. public enum InjectStyle {  
  2.       
  3.     /** 
  4.      * 通过method invoke方法进行注入 
  5.      */  
  6.     METHOD_INVOKE,  
  7.     /** 
  8.      * 通过反射方式直接注入 
  9.      */  
  10.     ATTR_REFLECTION  
  11.   
  12. }  
 
Java代码   收藏代码
  1. public enum InjectType {  
  2.       
  3.     BY_NAME,BY_TYPE,AUTO  
  4.   
  5. }  
 

并在XML文件中配置一下就可以了。

测试类:

 

Parent类表示父类:

Java代码   收藏代码
  1. public class Parent {  
  2.       
  3.     private byte bStr;  
  4.       
  5.     private int age;  
  6.       
  7.     private String name = "hello";  
  8.       
  9.     private Parent2 p2;  
  10.   
  11.     public String getName() {  
  12.         return name;  
  13.     }  
  14.   
  15.     public void setName(String name) {  
  16.         this.name = name;  
  17.     }  
  18.   
  19.     public void do1() {  
  20.         System.out.println("Parent.do1");  
  21.     }  
  22.   
  23.     public Parent2 getP2() {  
  24.         return p2;  
  25.     }  
  26.   
  27.     public void setP2(Parent2 p2) {  
  28.         this.p2 = p2;  
  29.     }  
  30.   
  31.     public int getAge() {  
  32.         return age;  
  33.     }  
  34.   
  35.     public void setAge(int age) {  
  36.         this.age = age;  
  37.     }  
  38.   
  39.     public byte getbStr() {  
  40.         return bStr;  
  41.     }  
  42.   
  43.     public void setbStr(byte bStr) {  
  44.         this.bStr = bStr;  
  45.     }  
  46.   
  47. }  

 子类继承至该父类:

Java代码   收藏代码
  1. @Component  
  2. @ParentInject(items=@InjectItem(attr="name",value="test"))  
  3. public class Sub extends Parent {  
  4.   
  5.     @PostConstruct  
  6.     public void init() {  
  7.         System.out.println("PostConstruct:" + getName());  
  8.     }  
  9.   
  10. }  
 
Java代码   收藏代码
  1. public class TestMain {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         ApplicationContext ctx = new ClassPathXmlApplicationContext("test-context.xml");  
  8.         Sub sub = ctx.getBean(Sub.class);  
  9.         System.out.println(sub.getName());  
  10.     }  
  11.   
  12. }  

输出:

PostConstruct:test
test
hello2

表明父类注入成功。

 当然这种方式可以有多种变形,其主要意思和方法1是差不多的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值