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
- beanDefinitionMap类型是ConcurrrntHashMap集合
- 存放beans.xml中的bean节点配置的bean对象的信息
2.1.1 table
- 在beanDefinitionMap中有属性table
- table使数组类型是ConcurrrntHashMap$Node
- 因为是数组所以可以存放很多的备案对象信息,就是beans.xml配置
- 初始化是512,当超过时,会自动扩容
例如上例:
- 通过hash算法我们的Car01对象的信息就保存在index=373位置
- 保存是以ConcurrrntHashMap$Node类型保存
- key就是beans.xml中配置的car01
- value就是car01对象的信息[属性/属性值/类信息/是不是懒加载]
2.2singletonObject
- 类型是ConcurrrntHashMap集合
- 存放初始化的对象(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);
- 按类型来获取 bean, 要求 ioc 容器中的同一个类的 bean 只能有一个, 否则会抛出异常 NoUniqueBeanDefinitionException
- 这种方式的应用场景:比如 XxxAction/Servlet/Controller, 或 XxxService 在一个线程 中只需要一个对象实例(单例)的情况
- 这里在说明一下: 在容器配置文件(比如 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 +'}';}
}
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. 当 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. 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;
但是却注入里面就是基于泛型这套机制完成的
说明泛型基类的依赖关系,被子类自动继承,并根据泛型找到对应的子类。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
