• Spring核心之IOC&反射


    什么是依赖:Spring 把相互协作的关系称为依赖关系。假如 A 组件调用了 B 组件的方法,我们可称A 组件依赖于 B 组件

    IOC思想:Spring容器来实现相互依赖对象的创建,协调工作。对象只需要关心业务逻辑本身就好了。从这方面来说,对象如何得到他的协作对象的责任被反转了(IOC、DI)。控制反转就是获得依赖对象的方式反转了由Spring来负责控制对象的生命周期和对象间的关系

    创建被调用者实例的工作通常由Spring 容器来完成,然后注入给调用者,因此也称为依赖注入

    依赖注入的 Spring 实现

    1、设值注入:设值注入是指 IoC 容器使用属性的 setting 方法来注入被依赖的实例。

    2、构造注入:除了设值注入,还有另一种注入方式,这种方式在构造实例时,已为其完成了依赖关系的初始化。这种利用构造器来设置依赖关系的方式,被称为构造注入。

    两种注入方式的对比

    1、相比之下,设值注入具有如下的优点:

    (1)、与传统的 JavaBean 的写法更相似,程序开发人员更容易理解、接受。通过 Setting 方法设定依赖关系显得更加直观、自然。
    (2)、对于复杂的依赖关系,如果采用构造注入,会导致构造过于臃肿,难以阅读。Spring 在创建 Bean 实例时,需要同时实例化其依赖的全部实例,因而导致性能下降。而使用设值注入,则能避免这些问题。
    (3)、尤其是在某些属性可选的情况下,多参数的构造器更加笨重。

    2、构造注入也不是绝对不如设值注入,在某些特定的场景下,构造注入比设值注入更优秀。构造注入也有如下优势:

    (1)、构造注入可以在构造器中决定依赖关系的注入顺序,有限依赖的优先注入。例如,组件中某些其他依赖关系的注入,尝尝需要依赖于 Datasource 的注入。采用构造注入,可以在代码中清晰地决定注入顺序。
    (2)、对于依赖关系无须变化的 Bean ,构造注入更有用处。因为没有 setting 方法,所有的依赖关系全部在构造器内设定。因此,无须担心后续代码对依赖关系产生的破坏。
    (3)、依赖关系只能在构造器中设定,则只有组件的创建者才能改变组件的依赖关系。对组件的调用者而言,组件内部的依赖关系完成透明,更符合高内聚的原则。

    两种方式总结:建议采用以设值注入为住,构造注入为辅的注入策略。对于依赖关系无须变换的注入,尽量采用构造注入;而其他的依赖关系的注入,则考虑采用设值注入

    参考:http://blog.csdn.net/a906998248/article/details/7514085

    IOC(控制反转)之中的核心是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。

    那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。

    ApplicationContext context = new FileSystemXmlApplicationContext(  "applicationContext.xml");   

    A a = (A) context.getBean("a"); 

    pojo类的属性也是可以通过Spring注入进去的。Spirng不但可以注入基本类型,而且可以注入像List,Map这样的类型。

    Map类型的配置:

     1 <bean id="test" class="Test">   
     2         <property name="testMap">   
     3             <map>   
     4                 <entry key="a">   
     5                     <value>1</value>   
     6                 </entry>   
     7                 <entry key="b">   
     8                     <value>2</value>   
     9                 </entry>   
    10             </map>   
    11         </property>   
    12     </bean>  
    View Code
    <bean id="userAction" class="com.dobestself.action.UserAction"
    scope="prototype">
    <property name="userBO" ref="userBO" /> 论property可以传递的类型,如果把ref换成value则直接传递字符串(值),如果传递另外的bean,则要用ref。如果传递Map,参考上文。
    </bean>


    Spring运行机制剖析:
      1 //定义一个Bean类,这个类用于存放一个Bean拥有的属性。
      2 /* Bean Id */  
      3     private String id;   
      4     /* Bean Class */  
      5     private String type;   
      6     /* Bean Property */  
      7  private Map<String, Object> properties = new HashMap<String, Object>();  
      8 /*接下来Spring 就开始加载我们的配置文件了,将我们配置的信息保存在一个HashMap中,HashMap的key就是Bean 的 Id ,HasMap 的value是这个Bean,只有这样我们才能通过context.getBean("animal")这个方法获得Animal这个类。我们都知道Spirng可以注入基本类型,而且可以注入像List,Map这样的类型,接下来就让我们以Map为例看看Spring是怎么保存的吧*/
      9 //Map配置可以像下面的
     10 <bean id="test" class="Test">   
     11         <property name="testMap">   
     12             <map>   
     13                 <entry key="a">   
     14                     <value>1</value>   
     15                 </entry>   
     16                 <entry key="b">   
     17                     <value>2</value>   
     18                 </entry>   
     19             </map>   
     20         </property>   
     21     </bean>  
     22 //Spring是怎样保存上面的配置
     23 if (beanProperty.element("map") != null) {   
     24                     Map<String, Object> propertiesMap = new HashMap<String, Object>();   
     25                     Element propertiesListMap = (Element) beanProperty   
     26                             .elements().get(0);   
     27                     Iterator<?> propertiesIterator = propertiesListMap   
     28                             .elements().iterator();   
     29                     while (propertiesIterator.hasNext()) {   
     30                         Element vet = (Element) propertiesIterator.next();   
     31                         if (vet.getName().equals("entry")) {   
     32                             String key = vet.attributeValue("key");   
     33                             Iterator<?> valuesIterator = vet.elements()   
     34                                     .iterator();   
     35                             while (valuesIterator.hasNext()) {   
     36                                 Element value = (Element) valuesIterator.next();   
     37                                 if (value.getName().equals("value")) {   
     38                                     propertiesMap.put(key, value.getText());   
     39                                 }   
     40                                 if (value.getName().equals("ref")) {   
     41                                     propertiesMap.put(key, new String[] { value   
     42                                             .attributeValue("bean") });   
     43                                 }   
     44                             }   
     45                         }   
     46                     }   
     47                     bean.getProperties().put(name, propertiesMap);   
     48                 }  
     49 /*接下来就进入最核心部分了,让我们看看Spring 到底是怎么依赖注入的吧,其实依赖注入的思想也很简单,它是通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。让我们看看具体它是怎么做的吧。 
     50 首先实例化一个类,像这样 */
     51 public static Object newInstance(String className) {   
     52         Class<?> cls = null;   
     53         Object obj = null;   
     54         try {   
     55             cls = Class.forName(className);   
     56             obj = cls.newInstance();   
     57         } catch (ClassNotFoundException e) {   
     58             throw new RuntimeException(e);   
     59         } catch (InstantiationException e) {   
     60             throw new RuntimeException(e);   
     61         } catch (IllegalAccessException e) {   
     62             throw new RuntimeException(e);   
     63         }   
     64         return obj;   
     65     }  
     66 //接着它将这个类的依赖注入进去,像这样
     67 public static void setProperty(Object obj, String name, String value) {   
     68         Class<? extends Object> clazz = obj.getClass();   
     69         try {   
     70             String methodName = returnSetMthodName(name);   
     71             Method[] ms = clazz.getMethods();   
     72             for (Method m : ms) {   
     73                 if (m.getName().equals(methodName)) {   
     74                     if (m.getParameterTypes().length == 1) {   
     75                         Class<?> clazzParameterType = m.getParameterTypes()[0];   
     76                         setFieldValue(clazzParameterType.getName(), value, m,   
     77                                 obj);   
     78                         break;   
     79                     }   
     80                 }   
     81             }   
     82         } catch (SecurityException e) {   
     83             throw new RuntimeException(e);   
     84         } catch (IllegalArgumentException e) {   
     85             throw new RuntimeException(e);   
     86         } catch (IllegalAccessException e) {   
     87             throw new RuntimeException(e);   
     88         } catch (InvocationTargetException e) {   
     89             throw new RuntimeException(e);   
     90         }   
     91 }  
     92 /*最后它将这个类的实例返回给我们,我们就可以用了。我们还是以Map为例看看它是怎么做的,我写的代码里面是创建一个HashMap并把该HashMap注入到需要注入的类中,像这样,*/
     93 if (value instanceof Map) {   
     94                 Iterator<?> entryIterator = ((Map<?, ?>) value).entrySet()   
     95                         .iterator();   
     96                 Map<String, Object> map = new HashMap<String, Object>();   
     97                 while (entryIterator.hasNext()) {   
     98                     Entry<?, ?> entryMap = (Entry<?, ?>) entryIterator.next();   
     99                     if (entryMap.getValue() instanceof String[]) {   
    100                         map.put((String) entryMap.getKey(),   
    101                                 getBean(((String[]) entryMap.getValue())[0]));   
    102                     }   
    103                 }   
    104                 BeanProcesser.setProperty(obj, property, map);   
    105             }  
    View Code

    反射:由对象反推类

     1 public static void printMethods(Class cl)
     2 {
     3 Method[] methods =cl.getDeclaredMethods();//返回一个包含方法对象的数组
     4 for(Method m : methods)//循环该类的每个方法
     5 {
     6 Class retType = m.getReturnType();//该方法的返回类型,
     7 Sting name = m.getName();//获得方法名
     8 Systen.out.print(" "+Modifier.toString(m.getModifiers());打印方法修饰符
     9 System.out.print(" "+retType.getName() + " " + name +"(");
    10 
    11 Class[] paramTypes = m.getParameterTypes();//获得一个方法参数数组(getparameterTypes用于返回一个描述参数类型的Class对象数组)
    12 
    13 for(int j = 0 ; j < paramTypes.length ; j++)
    14 
    15 {
    16 if ( j > 0 ) System.out.print(" , ");   //如果有多个参数,中间则用逗号隔开,否则直接打印参数
    17 System.out.print (paramTypes[ j ].getName);
    18 }
    19 System.out.println (" );");
    20 }} 
    21 
    22 //////////getparameterTypes方法用于返回一个描述参数类型的Class对象数组)
    View Code

    参考文献:

    http://blog.csdn.net/a906998248/article/details/7514085

    http://blog.csdn.net/it_man/article/details/4402245

  • 相关阅读:
    Java内存模型
    mysql通过“延迟关联”进行limit分页查询优化的一个实例
    RabbitMQ(二):相应机制、持久化、负载均衡分发
    RabbitMQ(一):安装配置、用户权限
    S7.Net与西门子PLC通讯——纯新手必看
    [.net core] 创建和发布NuGet包 (dotnet CLI)
    [收藏]2018年10月最新全网可用接码打码平台 [若快已挂]
    如何写出无法维护的代码
    C# ——Parallel类
    .net语音播放,自定义播报文字
  • 原文地址:https://www.cnblogs.com/dobestself-994395/p/4268869.html
Copyright © 2020-2023  润新知