自学spring真的需要自己多手动敲代码,了解弯弯绕绕的bean实例化的个中过程,去理解无参构造,静态工厂构造,实例工厂构造的区别,实现方法,理解bean的作用域,生命周期。
Bean对象的实例化需要spring帮我们实现,借助的中间媒介就是xml核心配置文件,其中的bean标签是bean对象实例化最重要的部分,来分析一下bean标签最基本的几个属性:
1、id:就是你随便规定的一个名称,在但是这个名称在你IOC容器实例化启用ApplicationContext接口定义客户端利用getBean(“id”)方法实例化bean的时候一定要注意里面的内容与你在xml文件里定义的对应bean标签id一致,我就出现过这样的错误导致报出未识别的错误。
2、class:顾名思义,class类,它的值是你需要借助它去实例化bean的一个java类的全限定名,个人理解就是目录里与xml文件对应的相对路径,这个java类可以是无参构造的原生类,也可以是作为中间商的静态或者实例工厂类。这个class的值可能有一些变化,有时候也可以不写这个属性,后面测试代码会给出来参考。
3、scope:作为比较受关注的属性,scope的两个值prototype与singleton的区别就很重要了,首先说当scope=“prototype”时实例化出来的对象的特点,定义这个值的时候每一次getBean之后(这里比较有特点,就是说scope等于prototype的时候,容器实例化之后对象并没有创建,而是在给出接收实例的接口,并运行getBea方法之后才能得到bean的实例化对象,属于半自动化了,我写多少条含接口含getBean代码就会产生多少个对象)得到的对象并不是同一个对象,也就是说它每次都会创建新对象,销毁的机制就有些像java一些自定义类的回收机制了,长时间不用会自动回收的。其次当scope=“singleton”的时候,实例化出来的对象都是同一个对象,无论你写多少行getBean代码,对象都是一个单例对象。有意思的是这种方式下创建对象的时间和spring容器实例化的时间一致,就是说我已经做好了橙汁,只需要你拿个接口杯子来装就行,全自动化。回收机制当然是与spring容器共存亡了。
4、还有其他的bean标签内部属性,会在代码里提到。
5、测试无参构造实例化bean以及bean标签内部属性scope取值不同的影响:
- UserDao.java
-
package com.hlc.dao; //这里采用的无参构造去构造bean public class UserDao implements UserDaoImpl{ // 这里的无参构造也可以尝试用来测试xml文件中bean属性scope等于不同值的作用,原理是容器构造一个对象时无参构造方法就会执行一次。 public UserDao(){ System.out.println("UserDao was created....."); } // 写一个初始化方法供xml文件帮助我使用,在bean里添加之后会在对象创建后初始化时调用它 public void init(){ System.out.println("init....."); } // 再加一个销毁的方法,会在bean销毁时使用到它,但可能销毁速度过快bean还没有反应过来调用它就会被销毁,所以这里需要注意在测试时用close();方法把app客户端关闭掉,当它关闭的时候bean会默认即将被销毁从而有时间调用它。 public void destroy(){ System.out.println("destroy....."); } @Override public void up() { System.out.println("up......."); } @Override public void shut() { System.out.println("shut down....."); } @Override public void inter() { System.out.println("inter....."); } }
- UserDaoImpl
-
package com.hlc.dao; public interface UserDaoImpl { void up(); void shut(); void inter(); }
- config-application.xml
-
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--利用bean去设定一个全限定名指向对应的类--> <!-- 测试scope=“prototype”的作用--> <!-- <bean id="userdao" class="com.hlc.dao.UserDao" scope="prototype"></bean>--> <!-- 通过classname.equals(class1name)套接if条件语句的方法测试到:scope等于singleton时创建的是同一实例对象,而prototype则创建的是不同对象 关于这个测试,也可以回看UserDaoTest类里的无参构造测试。--> <!-- 这里的init-method与destroy-method其实就是指定好bean能活多久的方法,指定的值应该在UserDao类里写好--> <bean id="userdao" class="com.hlc.dao.UserDao" init-method="init" destroy-method="destroy"></bean> </beans>
- UserDaoTest.java
-
import com.hlc.dao.UserDaoImpl; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserDaoTest { // 测试注解,需要在pom文件导入java单元测试框架junit的依赖项。 @Test public void test1() { // 这里的app相当于spring的一个容器访问客户端,用接口ApplicationContext定义,我们将会利用它去获取bean对象,当xml文件中的bean指定类的scope值为singleton时,一旦app被创建,也就是容器一实现,对象就已经被创建了,只是还没有利用getBean()方法让接口接收。由于我在UserDao类添加了无参构造方法,所以只执行这一步代码会输出单句UserDao was created....证明对象创建,同理当容器销毁时这个对象才会被销毁,它与容器共存亡。。但是当xml文件中的bean指定的类的scope值为prototype时,就算app创建,对象也只会在利用getBean()方法让接口接收时创建对象。这就导致了它创建多对象特性的形成。自然的这样模式下创建对象的生命会跟随bean一样,当长期不使用的时候就会被GC机制回收。一般spring项目会采用scope=“singleton”。 // ApplicationContext app = new ClassPathXmlApplicationContext("config-application.xml"); ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("config-application.xml"); // 接口接收。 UserDaoImpl user = (UserDaoImpl) app.getBean("userdao"); // UserDaoImpl user1 = (UserDaoImpl) app.getBean("userdao"); // 这是测试方法调用,感觉没啥意义。 // user.up(); // user.inter(); // user.shut(); // 下面是测试bean的scope值的作用代码,验证创建的是单例对象还是多例对象。下面要测试bean的生命周期所以把测试这个的先注掉啦! // if (user.equals(user1)) { // System.out.println("user = user1"); // } else System.out.println("user != user1"); // 注意这行代码ApplicationContext app = new ClassPathXmlApplicationContext("config-application.xml"); // 其中ApplicationContext是spring中最重要的两个接口中的一个,而后面的ClassApplicationContext是具体实现的上层应用类 // 功能比它多,比如这个close()方法ApplicationContext接口就没有配备,所以要想使用close();方法需要用这个类去接收。 // 需要将app的类型改动一下才能实现close()。改动后的代码如上述。 app.close(); // 补充: 结果显示bean销毁之前将UserDao类中的destroy()方法调用了。 } }
6、测试静态工厂实例化bean
- staticFactory.java
-
package com.hlc.factory; import com.hlc.dao.UserDao; import com.hlc.dao.UserDaoImpl; //主要测试静态工厂构造bean public class staticFactory { public static UserDaoImpl getUserDaoImpl(){ // 返回时new一个新的UserDao对象实现静态工厂的构造。 return new UserDao(); } }
- staticFactorytest.xml
-
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 为了区别于无参构造的测试,我违背了常理的测试结构,又建立了一个xml文件,在测试时更改ClassPathXmlApplicationContext("")中的xml文件名即可 这里我们利用静态工厂类去制造bean实例对象,factory-method的值是写好的静态方法,返回的是new出的一个新对象UserDao--> <bean id="userdao" class="com.hlc.factory.staticFactory" factory-method="getUserDaoImpl"></bean> </beans>
- staticFactoryTest.java
-
import org.springframework.context.support.ClassPathXmlApplicationContext; public class staticFactoryTest { @Test public void Test(){ // 此例子主要在测试静态工厂构造,个人理解原理就是将工厂作为UserDao与Xml之间的中间商,工厂提取UserDaoImpl中的类特性, // 接到app客户端口getBean()生产对象userdao的指令之后会按照类UserDao给出的图纸去制造,感觉这样子的商业模式 // 会起到一定的解耦作用。 ApplicationContext app = new ClassPathXmlApplicationContext("staticFactorytest.xml"); UserDaoImpl user = (UserDaoImpl) app.getBean("userdao"); System.out.println(user); } }
7、测试实例工厂实例化bean
- DynamicFactory.java
-
package com.hlc.factory; import com.hlc.dao.UserDao; import com.hlc.dao.UserDaoImpl; //此例采用实例工厂去实现bean的实例化 public class DynamicFactory { public UserDaoImpl getUserDaoImpl(){ // 返回时new一个新的UserDao对象实现静态工厂的构造。 return new UserDao(); } }
- DynamicFactory.xml
-
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--这里需要注意这个是静态工厂与实例工厂的使用区别,实例工厂需要先将工厂实例化,再去访问工厂的bean实例调用方法去制造UserDao的bean实例--> <bean id="factory" class="com.hlc.factory.DynamicFactory"></bean> <bean id="userdao" factory-bean="factory" factory-method="getUserDaoImpl"></bean> </beans>
- DynamicFactoryTest.java
-
import com.hlc.dao.UserDaoImpl; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class DynamicFactoryTest { @Test public void Test(){ // 测试结果的代码真的就一样。 ApplicationContext app = new ClassPathXmlApplicationContext("DynamicFactory.xml"); UserDaoImpl user = (UserDaoImpl) app.getBean("userdao"); System.out.println(user); } }
8、基于5去建立service层实现假web页面的功能
- UserService
-
package com.hlc.service; public interface UserService { void shut(); }
- UserServiceImpl.java
-
import com.hlc.dao.UserDaoImpl; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; //测试搭建service层帮我们去完成业务,这里采用spring帮我们完成,其实这个service作用就相当于相当于一个假的web页面。 public class UserServiceImpl implements UserService{ @Override public void shut() { ApplicationContext app = new ClassPathXmlApplicationContext("DynamicFactory.xml"); UserDaoImpl user = (UserDaoImpl) app.getBean("userdao"); user.shut(); } }
- UserServiceTest.xml
-
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="service" class="com.hlc.service.UserServiceImpl"></bean> </beans>
- UserServiceTest.java
-
import com.hlc.service.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserServiceTest { @Test public void Test(){ ApplicationContext a = new ClassPathXmlApplicationContext("UserServiceTest.xml"); UserService service = (UserService) a.getBean("service"); service.shut(); } }
9、总的pom.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Spring</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- 这里导入spring坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.15</version>
</dependency>
<!-- 这里导入的java单元测试框架的依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
10、测试练习的项目目录如下:
11、其实真的很水,卡了三天的进度,坚持日更吧只能.......