Java框架--Spring(轻量级容器框架)(入门+ioc)

目录

一.概念

海绵hong对于ioc的理解:

二.spring快速入门

1.最基本的spring实例

1.1javabean类

1.2beans.xml

 1.3 ioc容器使用

2.spring 容器结构/机制

 2.1beanDefinitionMap

2.2singletonObject

2.3beanDefinitionNames

2.4注意点

三.Spring 管理 Bean-IOC

1.Spring配置/管理bean介绍

1.2bean的基于xml文件配置方式

1.3通过ref来配置bean

1.4引用/注入内部bean对象(同ref使用场景类似)

1.5引用/注入集合/数组类型 

1.6级联属性赋值

1.7通过静态工厂获取对象 

1.8通过实例工厂获取对象

1.9通过FactoryBean获取对象(重点)

1.10bean 配置信息重用(继承)

1.11 bean创建顺序

1.12bean对象的单例和多例

1.13bean的生命周期

1.14配置 bean 的后置处理器(进行统一管理)

1.16基于XML的bean的自动装配

1.17spring el表达式

2.基于注解配置bean

2.1基本介绍

2.2快速入门

2.3手动开发简单的spring基于注解配置的程序

2.4自动装配

2.5泛型依赖注入


spring学习的核心内容

IOC:控制反转,可以管理Java工具

AOP : 切面编程

JDBCTemplate : 是 spring 提供一套访问数据库的技术, 应用性强,相对好理解

声明式事务: 基于 ioc/aop 实现事务管理,

IOC, AOP 是重点同时难点

一.概念

1.spring可以整合其他的框架(是管理框架的框架)

2.spring有两个核心技术:IOC和AOP

3.IOC [Inversion Of Control 反转控制]

传统的开发模式[Jdbcutils/反射]

程序--->环境    //程序读取配置环境,然后自己创建对象

图片解析(以数据库为例说明):

1、程序员编写程序, 在程序中读取配置信息

2. 创建对象, new Object???() // 反射方式

3. 使用对象完成任务

IOC 的开发模式 [EmpAction EmpService EmpDao Emp]

程序<-----容器 //容器创建好对象,程序直接使用.

图片解析

1、Spring 根据配置文件 xml/注解, 创建对象, 并放入到容器(ConcurrentHashMap)中,

并且可以完成对象之间的依赖

2、当需要使用某个对象实例的时候, 就直接从容器中获取即可

3、程序员可以更加关注如何使用对象完成相应的业务, (以前是 new ... ==> 注解/配置

方式)

4. DI—Dependency Injection 依赖注入,可以理解成是 IOC 的另外叫法.

5. Spring 最大的价值,通过配置,给程序提供需要使用的

web 层[Servlet(Action/Controller)]/Service/Dao/[JavaBean/entity]对象,

这个是核心价值所在,也是 ioc 的具体体现, 实现解耦

海绵hong对于ioc的理解:

        本来属于你控制的事情,交由别人来控制,而你只在需要的时候进行获取就可以,把创建对象的过程交给Spring来进行管理,从而做到将原来需要自己手动new对象,变成直接从Spring中获取。

为何我们要使用ioc哪?

        我们来想想当我们需要点菜的时候可以直接去new一个对象,但是如果我们需要多次点这个菜,不可能一个菜只有一个人去购买把。难道我们还需要继续去new这个类吗?这样只会增加代码冗余,但是当我们使用ioc之后,就会发现不论是一个人还是多个人点这个菜都会从ioc中获取,而且当菜的属性发生变化只需要修改ioc中的即可

二.spring快速入门

1.最基本的spring实例

1.1javabean

package com.hong.spring;/*** Created with IntelliJ IDEA.** @Author: 海绵hong* @Date: 2022/09/28/10:51* @Description: JavaBean对象*/public class Car {private String id;private String name;private Double price;public Car() { //在反射调用的时候会使用car的无参构造器}public Car(String id, String name, Double price) {this.id = id;this.name = name;this.price = price;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}@Overridepublic String toString() {return "Car{" +"id='" + id + '\'' +", name='" + name + '\'' +", price=" + price +'}';}}

1.2beans.xml

 1.3 ioc容器使用

package com.hong.spring;import org.springframework.context.support.ClassPathXmlApplicationContext;/*** Created with IntelliJ IDEA.** @Author: 海绵hong* @Date: 2022/09/28/10:55* @Description: 最基本的spring练习*/
public class CarAppication {public static void main(String[] args) {ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("beans.xml");Car car01 = ioc.getBean("car01", Car.class);System.out.println("car01="+car01);System.out.println(car01.getName());}}

2.spring 容器结构/机制

 2.1beanDefinitionMap

  1. beanDefinitionMap类型是ConcurrrntHashMap集合
  2. 存放beans.xml中的bean节点配置的bean对象的信息

2.1.1  table

  1. 在beanDefinitionMap中有属性table
  2. table使数组类型是ConcurrrntHashMap$Node
  3. 因为是数组所以可以存放很多的备案对象信息,就是beans.xml配置
  4. 初始化是512,当超过时,会自动扩容

例如上例:

  1. 通过hash算法我们的Car01对象的信息就保存在index=373位置
  2. 保存是以ConcurrrntHashMap$Node类型保存
  3. key就是beans.xml中配置的car01
  4. value就是car01对象的信息[属性/属性值/类信息/是不是懒加载]

2.2singletonObject

  1. 类型是ConcurrrntHashMap集合
  2. 存放初始化的对象(car01的属性名/属性值)

2.2.1table

  • 如果你在bean.xml文件中配置的对象是单例的就会初始化放在table中
  • 类型使ConcurrrntHashMap$Node

2.3beanDefinitionNames

  • 记录了我们在beans.xml中配置的bean的名称,方便查找

2.4注意点

如果在beans.xm中没有分配id系统会默认分配 id ,分配 id 的规则是 全类名#0 , 全类名#1 这样的规则来分配 id , 我们可以通过 debug 方式来查看。

三.Spring 管理 Bean-IOC

1.Spring配置/管理bean介绍

1.2bean的基于xml文件配置方式

1.2.1通过类型来获取bean

ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("beans.xml");Car car01 = ioc.getBean( Car.class);System.out.println("car01="+car01);
  1. 按类型来获取 bean, 要求 ioc 容器中的同一个类的 bean 只能有一个, 否则会抛出异常 NoUniqueBeanDefinitionException       
  2. 这种方式的应用场景:比如 XxxAction/Servlet/Controller, XxxService 在一个线程 中只需要一个对象实例(单例)的情况
  3. 这里在说明一下: 在容器配置文件(比如 beans.xml)中给属性赋值, 底层是通过 setter 方法完成的, 这也是为什么我们需要提供 setter 方法的原因

1.2.1 通过构造器配置bean(全参构造器)

constructor-arg标签可以指定使用构造器的参数

index表示构造器的第几个参数,从0开始计算

除了可以通过index,还可以通过那么/type初始化

   
 
    
使用细节 1. 通过 index 属性来区分是第几个参数 2. 通过 type 属性来区分是什么类型 ( 按照顺序 ) 1.2.2通过p名称空间配置bean

1.3通过ref来配置bean

spring ioc 容器 , 可以通过 ref 来实现 bean 对象的 相互引用 该元素用来将bean中指定属性的值设置为对容器中的另外一个bean的引用。 bean 对象的相互引用 1. 其它含义和前面一样 2. ref 表示 memberDAO 这个属性将引用/指向 id = memberDAOImpl 对象

比如某些场景下有多个数据源,项目连了多个数据库,就可以分开管理 

一个bean需要引用多个bean对象的时候就可以使用ref连接起来 不同的javabean对象也可以进行相互调用

1.4引用/注入内部bean对象(同ref使用场景类似)


1.5引用/注入集合/数组类型 

实例演示

package com.hong.spring.bean;import java.util.*;/*** @海绵hong* @version 1.0* Master类*/
public class Master {private String name;//主人名private List monsterList;private Map monsterMap;private Set monsterSet;//数组private String[] monsterName;//Java基础//这个Properties 是 Hashtable的子类 , 是key-value的形式//这里Properties  key和value 都是Stringprivate Properties pros;public String getName() {return name;}public void setName(String name) {this.name = name;}public List getMonsterList() {return monsterList;}public void setMonsterList(List monsterList) {this.monsterList = monsterList;}public Map getMonsterMap() {return monsterMap;}public void setMonsterMap(Map monsterMap) {this.monsterMap = monsterMap;}public Set getMonsterSet() {return monsterSet;}public void setMonsterSet(Set monsterSet) {this.monsterSet = monsterSet;}public String[] getMonsterName() {return monsterName;}public void setMonsterName(String[] monsterName) {this.monsterName = monsterName;}public Properties getPros() {return pros;}public void setPros(Properties pros) {this.pros = pros;}@Overridepublic String toString() {return "Master{" +"name='" + name + '\'' +", monsterList=" + monsterList +", monsterMap=" + monsterMap +", monsterSet=" + monsterSet +", monsterName=" + Arrays.toString(monsterName) +", pros=" + pros +'}';}
}
      monsterKey01monsterKey02 Java 工程师前端工程师大数据工程师 银角大王金角大王
使用细节 1. 主要掌握 List/Map/Properties 三种集合的使用 . 2. Properties 集合的特点 韩顺平 Java 工程师 1) 这个 Properties Hashtable 的子类 , key-value 的形式 2) key string value 也是 string 1.5.1 通过 util 名称空间来创建 list 集合 , 可以当做创建 bean 对象的工具来使用

三国演义西游记红楼梦水浒传

1.6级联属性赋值

spring ioc 容器 , 可以直接给对象属性的属性赋值, 即级联属性赋值
    

1.7通过静态工厂获取对象 

复习:

        静态代码块;作用就是对类进行初始化,而且它随这类的加载而执行,并且只会执行一次

        普通代码块:每创建一次对象就会执行。进行初始化内容

public class MyStaticFactory {private static Map monsterMap;static {monsterMap = new HashMap();monsterMap.put("monster_01", new Monster(100, "黄袍怪", "一阳指"));monsterMap.put("monster_02", new Monster(200, "九头金雕", "如来神掌"));}public static Monster getMonster(String key) {return monsterMap.get(key);}
}
2. 修改 beans.xml , 增加配置
  
 

1.8通过实例工厂获取对象

public class MyInstanceFactory {private Map monster_map; //非静态代码块{monster_map = new HashMap();monster_map.put("monster_01", new Monster(100, "猴子精", "吃人"));monster_map.put("monster_02", new Monster(200, "九头金雕", "如来神掌"));}public Monster getMonster(String key) {return monster_map.get(key);}
}

1.9通过FactoryBean获取对象(重点)

 
public class MyFactoryBean implements FactoryBean {private String keyVal;private Map monster_map;{monster_map = new HashMap();monster_map.put("monster_01", new Monster(100, "黄袍怪", "一阳指"));monster_map.put("monster_02", new Monster(200, "九头金雕", "如来神掌"));}public void setKeyVal(String keyVal) {this.keyVal = keyVal;}@Overridepublic Monster getObject() throws Exception { // TODO Auto-generated method stub return this.monster_map.get(keyVal);}@Overridepublic Class getObjectType() { // TODO Auto-generated method stub return Monster.class;}@Overridepublic boolean isSingleton() { // TODO Auto-generated method stub return true;}
}
   

1.10bean 配置信息重用(继承)

当我们需要一个bean对象和之前存在的bean对象属性相同,我们直接复制这样会造成数据冗余,所以我们可以使用Java基础中的继承来解决这个问题

  

1.11 bean创建顺序

说明 1. spring ioc 容器 , 默认是按照配置的顺序创建 bean 对象

会先创建 student01 这个 bean 对象,然后创建 department01 这个 bean 对象 2. 如果这样配置

会先创建 department01 对象,再创建 student01 对象 depends-on是这个bean依赖于后面的bean,就会先去创建depends-on属性的bean对象 bean对象是先创建bean对象之后在进行引用

1.12bean对象的单例和多例

说明         在 spring ioc 容器 , 在默认是按照单例创建的,即配置一个 bean 对象后, ioc 容器只会 创建一个 bean 实例。         如果, 我们希望 ioc 容器配置的某个 bean 对象,是以多个实例形式创建的则可以通过配置 scope="prototype" 来指定
使用细节 1. 默认是单例 singleton, 在启动容器时 , 默认就会创建 , 并放入到 singletonObjects 集合 2. 设置为多实例机制后 , bean 是在 getBean() 时才创 3. 如 果 是 单 例 singleton, 同 时 希 望 在 getBean 时 才 创 建 (从singletonObjects 集合中拿出来), 可 以 指 定 懒 加 载 lazy-init ="true" ( 注意默认是 false) 4. 通常情况下 , lazy-init 就使用默认值 false , 在开发看来 , 用空间换时间是值得的 , 除非 有特殊的要求 . 5. 如果 scope="prototype" 这时你的 lazy-init 属性的值不管是 ture, 还是 false 都是在 getBean 时候,才创建对象 .

1.13bean的生命周期

说明 : bean 对象创建是由 JVM 完成的,然后执行如下方法 1. 执行构造器 2. 执行 set 相关方法 3. 调用 bean 的初始化的方法(需要配置) 4. 使用 bean 5. 当容器关闭时候,调用 bean 的销毁方法(需要配置)
public class House {private String name;public House() {System.out.println("House() 构造器");}public String getName() {return name;}public void setName(String name) {System.out.println("House setName()...");this.name = name;}public void init() {//初始化方法(由程序员自己定义)System.out.println("House init()..");}public void destory() {//销毁方法(由程序员自己定义)System.out.println("House destory()..");}
}

  
   public void beanLife () {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");House house = ioc.getBean("house", House.class);System.out.println(house); //关闭容器((ConfigurableApplicationContext) ioc).close();//因为ConfigurableApplicationContext中有close方法,所以需要转型}
使用细节 1. 初始化 init 方法和 destory 方法 , 是程序员来指定 2. 销毁方法就是当关闭容器时,才会被调用 .

1.14配置 bean 的后置处理器(进行统一管理)

说明 1. spring ioc 容器 , 可以配置 bean 的后置处理器 2. 该处理器 / 对象会在 bean 初始化方法 调用前和初始化方法调用后被调用 3. 程序员可以在后置处理器中编写自己的代码

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;/*** @author 海绵hong* @version 1.0* 这是一个后置处理器, 需要实现 BeanPostProcessor接口*/
public class MyBeanPostProcessor implements BeanPostProcessor {/*** 什么时候被调用: 在Bean的init方法前被调用* @param bean 传入在IOC容器中创建/配置的Bean* @param beanName 传入在IOC容器中创建/配置Bean的id* @return Object 程序员对传入的bean 进行修改/处理【如果有需要的话】 ,返回* @throws BeansException*/@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessBeforeInitialization().. bean="+ bean + " beanName=" + beanName);//初步体验案例: 如果类型是House的统一改成 上海豪宅//对多个对象进行处理/编程==>切面编程if(bean instanceof House) {((House)bean).setName("上海豪宅~");}return null;}/*** 什么时候被调用: 在Bean的init方法后被调用* @param bean  传入的在IOC容器中创建/配置Bean* @param beanName 传入的在IOC容器中创建/配置Bean的id* @return 程序员对传入的bean 进行修改/处理【如果有需要的话】 ,返回* @throws BeansException*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessAfterInitialization().. bean="+ bean + " beanName=" + beanName);return bean;}
}
   

其它说明 1 、怎么执行到这个方法 ?=> 使用 AOP( 反射 + 动态代理 +IO+ 容器 + 注解 ) 2 、有什么用? => 可以对 IOC 容器中所有的对象进行统一处理 , 比如 日志处理 / 权限的校 / 安全的验证 / 事务管理 . - 初步体验案例 : 如果类型是 House 的统一改成 上海豪宅 3 、针对容器的所有对象吗 ? 是的 => 切面编程特点 4,属性文件有中文需要转成unicode编码(去网站进行转化) 1.15通过属性文件给文件bean注入值 1. src/ 创建 my.properties
name=\u9EC4\u888D\u602A
id=10
skill=\u72EE\u5B50\u543C
2. 修改 src\beans.xml , 继续完成配置

1.16基于XML的bean的自动装配

D:\idea_java_projects\spring5\src\com\hong\spring\dao\OrderDao.java D:\idea_java_projects\spring5\src\com\hong\spring\service\OrderService.java D:\idea_java_projects\spring5\src\com\hong\spring\action\OrderAction.java
 

1.17spring el表达式

1. Spring Expression Language Spring 表达式语言,简称 SpEL 。支持运行时查询并可以操 作对象。 2. EL 表达式一样, SpEL 根据 JavaBean 风格的 getXxx() setXxx() 方法定义的属性访问 对象 3. SpEL 使用 #{…} 作为定界符,所有在大框号中的字符都将被认为是 SpEL 表达式。 4. 不是重点 ,如果看到有人这样使用,能看懂即可

2.基于注解配置bean

2.1基本介绍

基于注解的方式配置 bean, 主要是项目开发中的组件,比如 Controller Service 、和 Dao. 组件注解的形式有 1. @Component 表示当前注解标识的是一个组件 2. @Controller 表示当前注解标识的是一个控制器,通常用于 Servlet 3. @Service 表示当前注解标识的是一个处理业务逻辑的类,通常用于 Service 韩顺平 Java 工程师 4. @Repository 表示当前注解标识的是一个持久化层的类,通常用于 Dao

2.2快速入门

package com.hong.spring.component;
import org.springframework.stereotype.Repository;/*** * @author 海绵hong* * @version 1.0*/
@Repository
public class UserDao {}package com.hspedu.spring.component;import org.springframework.stereotype.Service;/*** @author 海绵hong*  * @version 1.0*  */
@Service
public class UserService {}package com.hong.spring.component;
import org.springframework.stereotype.Controller;/*** @author*  海绵hong*  * @version 1.0 *  */
@Controller
public class UserAction {}
package com.hong.spring.component;
import org.springframework.stereotype.Component;/*** @author 海绵hong*  * @version 1.0 *  */
@Component
public class MyComponent {}}

配置beans.xml

含义是:当spring容器创建/初始化时,就会扫描这个包下的所以的有注解@Controller / @Service / @Respository / @Component 的类,将其类实例化,生成对象,放入到ioc容器

       public void getBeanByAnnotation () {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");UserAction userAction = ioc.getBean(UserAction.class);System.out.println(userAction);UserDao userDao = ioc.getBean(UserDao.class);System.out.println(userDao);MyComponent myComponent = ioc.getBean(MyComponent.class);System.out.println(myComponent);UserService userService = ioc.getBean(UserService.class);System.out.println(userService);}

注意事项和细节说明

1. 可以使用通配符 * 来指定 ,比如 com.hspedu.spring.* 表示 2.提问 : com.hspedu.spring.component 会不会去扫描它的子包 ? 答:会的 3. Spring IOC 容器不能检测一个使用了 @Controller 注解的类到底是不是一个真正的控 制器。注解的名称是用于程序员自己识别当前标识的是什么组件。其它的 @Service @Repository 也是一样的道理 [ 也就是说 spring IOC 容器只要检查到注解就会生成对象, 但是这个注解的含义 spring 不会识别,注解是给程序员编程方便看的 ] 4.

resource-pattern="User*.class": 表示只扫描满足要求的类(只扫描User打头的类)使用的少,不想扫描,不写注解就可以,

5. 需求:如果我们希望排除某个包/子包下的某种类型的注解,可以通过exclude-filter来指定
        1. context:exclude-filter 指定要排除哪些类
        2. type 指定排除方式 annotation表示按照注解来排除
        3. expression="org.springframework.stereotype.Service" 指定要排除的注解的全路径
 
6. 指定自动扫描哪些注解类
   
7.默认情况:标记注解后, 类名首字母小写作为 id 的值 。也可以使用注解的 value 属性 指定 id 值,并且 value 可以省略。
@Controller(value="userAction01");
@Controller("userAction01");

2.3手动开发简单的spring基于注解配置的程序

2.3.1需求说明

1. 自 己 写 一 个 简 单 的 Spring 容 器 , 通 过 读 取 类 的 注 解 (@Component @Controller @Service @Reponsitory) ,将对象注入到 IOC 容器 2. 也就是说,不使用 Spring 原生框架,我们自己使用 IO+Annotaion+ 反射 + 集合 技术实 , 打通 Spring 注解方式开发的 技术痛点 2.3.2思路分析

2.3.3代码实现

package com.hong.spring.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** Created with IntelliJ IDEA.** @Author: 海绵hong* @Date: 2022/10/06/15:44* @Description:* 1.@Target(ElementType.TYPE)指定我们的HongComponentScan注解可以修饰type程序元素* 2.@Retention(RetentionPolicy.RUNTIME)指定HongComponentScan注解的保留范围* 3. String value() default ""; 表示ComponentScan 可以传入 value*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HongComponentScan {String value() default "";
}
package com.hong.spring.annotation;/*** Created with IntelliJ IDEA.** @Author: 海绵hong* @Date: 2022/10/06/15:54* @Description:*这是一个配置类, 作用类似我们原生spring的 beans.xml 容器配置文件*/
@HongComponentScan(value = "com.hong.spring.component")
public class HongSpringConfig {}
package com.hong.spring.annotation;import com.hspedu.spring.hspapplicationcontext.HspApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMa
import java.util.concurrent.ConcurrentHashMap;/*** Created with IntelliJ IDEA.** @Author: 海绵hong* @Date: 2022/10/06/20:53* @Description: HongSpringApplicationContext类的作用类似spring原生ioc容器*/
public class HongSpringApplicationContext {private Class configClass;//ioc我存放的就是通过反射创建的对象(基于注解方式)private final ConcurrentHashMap ioc =new ConcurrentHashMap<>();//构造器public HongSpringApplicationContext(Class configClass) {this.configClass = configClass;//System.out.println("this.configClass=" + this.configClass);//获取要扫描的包//1. 先得到HongSpringConfig配置的的@ComponentScan(value = "com.hong.spring.component")ComponentScan componentScan =(ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);//2. 通过componentScan的value=> 即要扫描的包String path = componentScan.value();System.out.println("要扫描的包= " + path);//得到要扫描的包下的所有资源(类 .class)//1.得到类的加载器ClassLoader classLoader =HongSpringConfig.class.getClassLoader();//2. 通过类的加载器获取到要扫描的包的资源 url=》类似一个路径path = path.replace(".", "/");//一定要把. 替换成 /URL resource =classLoader.getResource(path);System.out.println("resource=" + resource);//3. 将要加载的资源(.class) 路径下的文件进行遍历=>ioFile file = new File(resource.getFile());if (file.isDirectory()) {File[] files = file.listFiles();for (File f : files) {System.out.println("=====================");System.out.println("=" + f.getAbsolutePath());//D:\hong_spring\spring\out\production\spring\com\hong\spring\component\UserService.class//获取到 com.hpng.spring.component.UserServiceString fileAbsolutePath = f.getAbsolutePath();//这里我们只处理.class文件if (fileAbsolutePath.endsWith(".class")) {//1. 获取到类名String className =fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));//System.out.println("className=" + className);//2. 获取类的完整的路径(全类名)//老师解读 path.replace("/",".") => com.hspedu.spring.component.String classFullName = path.replace("/", ".") + "." + className;//System.out.println("classFullName=" + classFullName);//3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..try {//这时,我们就得到老该类的Class对象//Class clazz = Class.forName(classFullName)//这里说一下//1. Class clazz = Class.forName(classFullName) 可以反射加载类//2. classLoader.loadClass(classFullName); 可以反射类的Class//3. 区别是 : 上面方式后调用来类的静态方法, 下面方法不会//4. aClass.isAnnotationPresent(Component.class) 判断该类是否有 @ComponentClass aClass = classLoader.loadClass(classFullName);if (aClass.isAnnotationPresent(Component.class) ||aClass.isAnnotationPresent(Controller.class) ||aClass.isAnnotationPresent(Service.class) ||aClass.isAnnotationPresent(Repository.class)) {//这里老师演示一个Component注解指定value,分配id//老师就是演示了一下机制.if(aClass.isAnnotationPresent(Component.class)) {//获取到该注解Component component = aClass.getDeclaredAnnotation(Component.class);String id = component.value();if(!"".endsWith(id)) {className = id;//替换}}//这时就可以反射对象,并放入到容器中Class clazz = Class.forName(classFullName);Object instance = clazz.newInstance();//放入到容器中, 将类名的首字母小写作为id//StringUtilsioc.put(StringUtils.uncapitalize(className) , instance);}} catch (Exception e) {e.printStackTrace();}}}}}//编写方法返回对容器中对象public Object getBean(String name) {return ioc.get(name);}
}
package com.hong.spring.annotation;import com.hong.spring.Hong;/*** Created with IntelliJ IDEA.** @Author: 海绵hong* @Date: 2022/10/08/10:21* @Description:*/
public class HongSpringApplicationContextTest {public static void main (String[]args){HongSpringApplicationContext ioc =new HongSpringApplicationContext(HongSpringConfig.class);UserAction userAction = (UserAction) ioc.getBean("userAction");System.out.println("userAction" + userAction);MyComponent myComponent = (MyComponent) ioc.getBean("myComponent");System.out.println("myComponent" + myComponent);UserService userService = (UserService) ioc.getBean("userService");System.out.println("userService=" + userService);UserDao userDao = (UserDao) ioc.getBean("userDao");System.out.println("userDao=" + userDao);System.out.println("ok");}
}
注意事项和细节说明         还可以通过@Component(value = "xx") @Controller(value = "yy") @Service(value = "zz") 中指定的 value, bean 分配 id

2.4自动装配

基本说明 1. 基于注解配置 bean ,也可实现自动装配(在xm中使用ref进行自动装配),使用的注解是: @AutoWired 或者 @Resource 2. @AutoWired 的规则说明        spring会默认优先根据(被注解修饰的)属性类型去容器中找对应的组件(bean),找到就赋值;若找到多个相同类型的组件,再将属性的名称作为组件(bean)的id去容器中查找。 3. @Resource 的规则说明         1) @Resource 有两个属性是比较重要的 , 分是 name type,Spring @Resource 注解的 name 属性解析为 bean 的名字 , type 属性则解析为 bean 的类型 . 所以如果使用 name , 则使用 byName 的自动注入策略 , 而使用 type 属性时则使用 byType 自动注入策略         2) 如果 @Resource 没有指定 name type , 则先使用 byName 注入策略 , 如果匹配不上 , 再使用 byType 策略 , 如果都不成功,就会报错 4. 建议,不管是 @Autowired 还是 @Resource 都保证属性名是规范的写法就可以 注入
@Controller
public class UserAction {//xml配置 ref//说明 @Autowired//1)在IOC容器中查找待装配的组件的类型,如果有唯一的bean匹配(按照类型),则使用该bean装配//2)如待装配的类型对应的bean在IOC容器中有多个,则使用待装配的属性的属性名作为id值再进行查找,//  找到就装配,找不到就抛异常//@Autowired//说明 @Resource//1) @Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,//  而type属性则解析为bean的类型.所以如果使用name属性,则使用byName的自动注入策略,//  而使用type属性时则使用byType自动注入策略//  比如@Resource(name = "userService") 表示装配 id=userService对对象//  比如@Resource(type = UserService.class) 表示按照UserService.class类型进行装配, 这时要求容器中,只能有一个这样类型的对象//2) 如果@Resource 没有指定 name 和 type ,则先使用byName注入策略,//   如果匹配不上, 再使用byType策略, 如果都不成功,就会报错//=================================//说明: @Autowired + @Qualifier(value = "userService02") 组合也可以完成指定 name/id 来进行自动装配//指定id进行组装, 也可以使用@Autowired 和 @Qualifier(value = "userService02")// 这时,是装配的 id=userService02 , 需要两个注解都需要写上@Resourceprivate UserService userService;public void sayOk() {System.out.println("UserAction 的sayOk()");System.out.println("userAction 装配的 userService属性=" + userService);userService.hi();}
}

2.5泛型依赖注入

基本说明 1. 为了更好的管理有继承和相互依赖的 bean 的自动装配,spring 还提供基于泛型依赖的 注入机制 2. 在继承关系复杂情况下,泛型依赖注入就会有很大的优越性

传统方法是将 PhoneDao /BookDao 自动装配到 BookService/PhoneSerive 中,当这 种继承关系多时,就比较麻烦,可以使用 spring 提供的泛型依赖注入

但是当我们

@Service 
public class PhoneService extends BaseService { 
}

 PhoneService里面没有写

private PhoneDao Phonedao;

但是却注入里面就是基于泛型这套机制完成的

说明泛型基类的依赖关系,被子类自动继承,并根据泛型找到对应的子类。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部