spring框架bean注入
今天学习了spring框架,刚刚入门简单的了解了spring并学习了bean的注入IOC:IOC(Inversion of Control,控制反转)不是什么技术,而是一种设计思想。它的目的是指导我们设计出更加松耦合的程序。
引入:
使用简单代码来实现推演 ,创建一个maven项目,开始我们的推演
创建一个bean类即常说的实体类如下:
我们创建一个测试类 springTest,在测试类中操作,怎么样来获取Student类中 的信息呢(student类中有构造方法,无参,有参,有get,set方法,有studay() 方法 等等)
我们要怎么样来获取对象呢:
1.直接获取:
@Test public void springTest() { Student student = new Student(); student.getStudy(); /* * 输出 学生在学习 * */ }
上述代码是否显得太low了,因为假若有n个类使用这个对像,我们要在每一个类中new,假若你要修改,这样的一个工程量会有点大。
2.工具类获取:
我们创建工具类来减少耦合性,在修改维护时只要修改工具类就行 代码调用:
@Test public void springTest02() { Student stu = StudentBean.getStu(); stu.getStudy(); /* * 输出 学生在学习 * */ }
这样就减少了一定的耦合性能,但在实际运用中,我们只可能只有一个实体类嘛当然不可能,如何提升性能并减少代码的耦合性呢
我们采用配置文件的方法建一个 beans.properties 存放bean的配置文件,并多创建一个实体类user
重新再创建一个工具类BeanFactroy来编写我们的最终代码:
public class BeanFactory { // 创建map集合存储对象 private static Map<String, Object> beanMap = new HashMap<String, Object>(); /* * 在类初始化时读取beans配置文件中所有的bean类存储到map集合中 * */ static { try { ResourceBundle beans = ResourceBundle.getBundle("beans");// 读取beans配置文件 Enumeration<String> keys = beans.getKeys(); // 获取所有key值 while (keys.hasMoreElements()) { String key = keys.nextElement(); // 获取每个key String className = beans.getString(key); // 获取value Class<?> aClass = Class.forName(className); // 通过反射得到该类 Object o = aClass.newInstance(); // 通过反射机制创建该类对象 beanMap.put(key, o); // 将k v值存入beanMap集合中 } } catch (Exception e) { e.printStackTrace(); } } /* 创建静态方法供外界调用 * */ public static Object getBean(String beanName) { return beanMap.get(beanName); } }
上面是工具类,下面是测试:
@Test public void springTest03() { User user = (User) BeanFactory.getBean("user"); user.getStudy(); /* * 输出 我在学习 * */ } @Test public void springTest04() { Student stu = (Student) BeanFactory.getBean("student"); stu.getStudy(); /* * 输出 学生在学习 * */ }
上面的实例简单的展示来如何减少耦合性,最终下来,在管理对象时,我们只需要修改beans.properties 文件即可,更加方便管理下面进入spring的ioc容器使用
Bean容器注入:
第一步导包:
<properties> <spring.version>5.2.9.RELEASE</spring.version> <junit-version>5.6.2</junit-version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>${junit-version}</version> </dependency> </dependencies>
第二步创建配置文件 applicationContext.xml (认准下面的步骤)
完成后如下:
开始编写:
通过构造方法获取对象:
测试代码:
/* * 读取app.xml文件 抽取出来 * */ private ApplicationContext ac = new ClassPathXmlApplicationContext("app.xml"); @Test public void springTest05() { User user1 = (User) ac.getBean("user1"); // user1与app.xml中bean里面的id值相对应 user1.getStudy(); // 打印 我在学习 }
读取xml方法:
- ClassPathXmlApplicationContext: 从classpath目录读取配置文件
- FileSystemXmlApplicationContext: 从文件系统或者url中读取配置文件
- AnnotationConfigApplicationContext:当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器,它用来读取注解。
使用前面的工厂来获取对象:
测试代码:
@Test public void springTest06() { User user1 = (User) ac.getBean("user2"); // user1与app.xml中bean里面的id值相对应 user1.getStudy(); // 打印 我在学习 }
在操作这里的时候我将BeanFactory修改了一点:
public class BeanFactory { private String beanName; private static Map<String, Object> beansObjectHashMap = new HashMap<String, Object>(); public BeanFactory() { } public BeanFactory(String beanName) { this.beanName = beanName; } /* * 采用静态代码块,在程序开始时,就将所有的对象存在beansObjectHashMap map集合中,使用时直接调用 * */ static { try { ResourceBundle beans = ResourceBundle.getBundle("beans"); Enumeration<String> keys = beans.getKeys(); while (keys.hasMoreElements()) { String key = keys.nextElement(); String className = beans.getString(key); Class<?> aClass = Class.forName(className); Object o = aClass.newInstance(); beansObjectHashMap.put(key, o); } } catch (Exception e) { e.printStackTrace(); } } // 采用配置文件获取对象 只能 获取一个 public static Object getBeanUser(String beanName) { try { ResourceBundle bundle = ResourceBundle.getBundle("beans"); String string = bundle.getString(beanName); Class<?> aClass = Class.forName(string); Object o = aClass.newInstance(); return o; } catch (Exception e) { e.printStackTrace(); return null; } } /* * 当有多个实体类时 封装一个map集合返回 * */ public static Object getBeanMap(String beanName) { return beansObjectHashMap.get(beanName); } /* public Object getBeanMap() { return beansObjectHashMap.get(this.beanName); }*/ }
Bean单例与多例:
<!-- Bean单例与多例,在bean容器中添加有个scope属性,singleton代表单例 prototype 代表多例,单例获取的对象地址值是相同的,多例是不同的 调用案例就一样的不写了 --> <bean id="user3" class="com.code.spring01.entity.User" scope="singleton"></bean> <!-- 单例 --> <bean id="user4" class="com.code.spring01.entity.User" scope="prototype"></bean> <!-- 多例 --> <!-- 单例生命周期:容器创建时,就创建对象;容器摧毁时,就摧毁对象。 多例生命周期:getBean方法被调用时,创建对象,对象销毁与spring无关,等待垃圾回收机制回收 -->
set方法注入:
<!-- 使用set注入时,bean类中需存在get set 方法 set 方法注入 property和constructor-arg 使用时的区别 (不用在意顺序)property注入时可以单个属性的注入,即想写几个属性就写几个(不能超过) constructor-arg 注入时,需全部属性都注入,否则会报错 --> <bean id="stu2" class="com.code.spring01.entity.Student"> <property name="age" value="19"></property> <property name="name" value="张三"></property> </bean> <!-- <bean id="stu2" class="com.code.spring01.entity.Student"> <constructor-arg name="name" value="张三"></constructor-arg> </bean>--> <!-- set 注入的简写 方式 --> <bean id="stu3" class="com.code.spring01.entity.Student" p:name="王五" p:pwd="123" p:age="31" p:sex="男"/>
集合属性注入:
实体类:
public class Tec { // 基本属性 private Integer id; private String username; private String password; private Address address; //list set array private String[] str; private List<String> list; private Set<String> set; //map properties private Map<String,String> map; private Properties properties; // 省略了set方法
bean注入:
<bean id="user" class="com.hopu.ioc.User"> <property name="str"> <array> <value>EE</value> <value>FF</value> </array> </property> <property name="list"> <list> <value>AA</value> <value>BB</value> </list> </property> <property name="set"> <set> <value>CC</value> <value>DD</value> </set> </property> <property name="map"> <map> <entry key="GG" value="gg"/> <entry key="HH" value="hh"/> </map> </property> <property name="properties"> <props> <prop key="II">ii</prop> <prop key="JJ">jj</prop> </props> </property> </bean>
Bean的多模块注入:
当项目过于庞大时,为了开发便于维护和可读性,我们可以将bean配置文件模块化,采用导入模块方式优化管理
<!-- 在app.xml中导入app2.xml文件 --> <import resource="app2.xml"/>
注解注入:
这个我没学,在百度上看了,简单模仿这操作一番:
@Component("admin") // 等同于bean id="admin" class="com.code.spring01.entity.Admin"></bean> @Scope(scopeName = "singleton") // 限制创建的为单例对象 //@Scope(scopeName = "prototype") // 限制创建的为多例对象 public class Admin { private String name; private String color; public Admin(String name, String color) { this.name = name; this.color = color; } public Admin() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return color; } public void setAge(String color) { this.color = color; } @Override public String toString() { return "Admin{" + "name='" + name + '\'' + ", color='" + color + '\'' + '}'; } }
私有成员变量注入:
@Value("BMW") private String name; @Value("Red") private String color;
set方法注入:
@Value("BMW") public void setName(String name) { this.name = name; } @Value("Red") public void setColor(String color) { this.color = color; }
在使用时当然是bean容器更加方便管理一些,代码耦合性也低
个人学习,内容简略。