本篇博客内容
web Helloworld
TestDao.java
package dao;
public interface TestDao {
public void sayHello();
}
TestDaoImpl.java
package dao;
public class TestDaoImpl implements TestDao{
public void sayHello() {
System.out.println("Hello asdasf");
}
}
配置 applicationContext.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="testDao" class="dao.TestDaoImpl"></bean>
</beans>
创建servlet:HelloServlet.java
其中doGet函数:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext application = request.getServletContext();
//WebApplicationContext context = (WebApplicationContext)application.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(application);
TestDao testDao = context.getBean("testDao",TestDao.class);
testDao.sayHello();
}
index.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<a href="hello">hello fuck you</a>
</body>
</html>
普通helloworld用一个Junit Test
@Test
void test1() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
TestDao testDao = context.getBean("testDao",TestDao.class);
testDao.sayHello();
}
依赖注入
依赖注入有两种方式,一种是构造方法注入,另一种是属性setter方法注入。
配置 spring-di.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="book" class="dao.Book">
<property name="isbn" value="0001"></property>
<property name="name" value="effective java"></property>
<property name="price" value="80.6"></property>
</bean>
<bean id="book1" class="dao.Book">
<constructor-arg value="0002" index="0"></constructor-arg>
<constructor-arg value="56.3" index="2"></constructor-arg>
<constructor-arg value="python" index="1"></constructor-arg>
</bean>
</beans>
<property>标签为 setter 注入。
<constructor-arg>标签为 构造器注入
Junit Test:
void testDi() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-di.xml");
Book book = (Book)context.getBean("book1");
//Book book = (Book)context.getBean("book");
System.out.println(book);
}
使用value子标签及<![CDATA[]]>
处理特殊属性值。
如果value值里有特殊字符,如:
<property name="name" value="1+1<2"></property>
这时由于value="1+1<2"会出错,应该使用<![CDATA[]]>
spring-di.xml:
<bean id="book" class="dao.Book">
<property name="isbn" value="0001"></property>
<property name="name">
<value><![CDATA[1+1<2?]]></value>
</property>
<property name="price" value="80.6"></property>
</bean>
Junit:
@Test
void testDi() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-di.xml");
Book book = (Book)context.getBean("book");
System.out.println(book);
}
注入使用引用
<bean id="book" class="dao.Book">
<property name="isbn" value="0001"></property>
<property name="name">
<value><![CDATA[1+1<2?]]></value>
</property>
<property name="price" value="80.6"></property>
<property name="author" ref="author"></property>
</bean>
<bean id="book1" class="dao.Book">
<constructor-arg value="0002" index="0"></constructor-arg>
<constructor-arg value="56.3" index="2"></constructor-arg>
<constructor-arg value="python" index="1"></constructor-arg>
<constructor-arg ref="author" index="3"></constructor-arg>
</bean>
<bean id="author" class="dao.Author">
<property name="name" value="Jinondo"></property>
<property name="age" value="21"></property>
</bean>
注意里面不是 value="",而是 ref=""
也可以直接用内部类
<bean id="book" class="dao.Book">
<property name="isbn" value="0001"></property>
<property name="name">
<value><![CDATA[1+1<2?]]></value>
</property>
<property name="price" value="80.6"></property>
<property name="author">
<bean class="dao.Author">
<property name="name" value="T0wn"></property>
<property name="age" value="18"></property>
</bean>
</property>
</bean>
Bean的属性为集合类型:Array, List, Set, Map
<bean id="author" class="dao.Author">
<property name="name" value="Jinondo"></property>
<property name="age" value="21"></property>
<property name="interest">
<list>
<value>Reading</value>
<value>Dancing</value>
</list>
</property>
</bean>
或者是 map 等
<map>
<entry key="" value=""></entry>
</map>
或 value 为引用
<map>
<entry key="" value-ref=""></entry>
</map>
还有一种办法是定义在外面
首先要有util的引用资源
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd"
>
<util:list id="interestList">
<value>Singing</value>
<value>exercise</value>
</util:list>
<bean id="author" class="dao.Author">
<property name="name" value="Jinondo"></property>
<property name="age" value="21"></property>
<property name="interest" ref="interestList"></property>
</bean>
bean的实例化
在面向对象的程序中,想要使用某个对象,就需要先实例化这个对象。同样,在Spring中,要想使用容器中的Bean,也需要实例化Bean。实例化Bean有三种方式,分别为构造器实例化、静态工厂方式实例化和实例工厂方式实例化(其中最常用的是构造器实例化)。
提示:在前面的例子中都是使用构造器实例化
静态工厂方法实例化
静态工厂是实例化Bean的另一种方式。该方式要求自己创建一个静态工厂的方法来创建Bean的实例。
- 创建 MyBean.class。成员变量为name和age
- 创建 MyBean2Factory.class
public class MyBean2Factory {
public static MyBean createBean(){
return new MyBean("Jinondo",20);
}
}
- 配置 spring-create.xml
<bean id="bean1" class="dao.MyBean2Factory" factory-method="createBean">
<property name="name" value="wdnmd"></property>
</bean>
- 调用测试
@Test
void testCreate() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-create.xml");
MyBean bean1 = (MyBean)context.getBean("bean1",MyBean.class);
System.out.println(bean1);
}
实例工厂方式实例化
实例工厂是采用直接创建Bean实例的方式,在配置文件中,通过factory-bean属性配置一个实例工厂,然后使用factory-method属性确定使用工厂中的哪个方法。
- 创建 MyBean.class。成员变量为name和age
- 创建 MyBean3Factory.class
public class MyBean3Factory {
public MyBean createBean(){
return new MyBean();
}
}
- 配置 spring-create.xml
<bean id="beanFactory" class="dao.MyBean3Factory"></bean>
<bean id="bean2" factory-bean="beanFactory" factory-method="createBean">
<property name="name" value="g-dragon"></property>
<property name="age" value="33"></property>
</bean>
4.调用测试
@Test
void testCreate() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-create.xml");
MyBean bean2 = (MyBean)context.getBean("bean2",MyBean.class);
System.out.println(bean2);
}
bean 的作用域
-
单例 singleton (为默认形式)
singleton 是 Spring容器默认的作用域,当 Bean 的作用域为 singleton 时,Spring 容器就只会存在一个共享的 Bean实例。singleton 作用域对于无会话状态的Bean(如 Dao 组件、Service 组件)来说,是最理想的选择。
<bean id="student" class="dao.Student" scope="singleton"></bean>
测试
@Test
void testLifecycle() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
Student student1 = context.getBean("student",Student.class);
Student student2 = context.getBean("student",Student.class);
System.out.println(student1==student2);
}
结果为 true
-
原型 prototype
对需要保持会话状态的 Bean(如Struts 2的 Action类)应该使用 prototype作用域。在使用 prototype作用域时,Spring容器会为每个对该 Bean的请求都创建一个新的实例。
<bean id="student" class="dao.Student" scope="prototype"></bean>
与上同一程序测试为 false
•singleton: 单例的(默认值), 在整个IOC容器中只存在一个bean的对象。 而且在IOC容器对象被创建时,就创建单例的bean的对象。 后续每次通过getBean()方法获取bean对象时,返回的都是同一个对象。
•prototype: 原型的,在整个IOC容器中可有多个bean的对象。在IOC容器对象被创建时, 不会创建原型的bean的对象。而是等到每次通过getBean()方法获取bean对象时,才会创建一个新的bean对象返回。
bean 的生命周期
-
singleton作用域
Spring容器可以管理singleton作用域的Bean的生命周期,在此作用域下,Spring能够精确的知道该Bean何时被创建,何时初始化完成,以及何时被销毁。 -
prototype作用域
prototype作用域的Bean,Spring只负责创建,当容器创建了Bean实例后,Bean的实例就交给客户端代码来管理,Spring容器将不再跟踪其生命周期。
<bean id="student" class="dao.Student" scope="singleton" init-method="init" destroy-method="destroy">
<property name="name" value="cyt"></property>
<property name="age" value="21"></property>
</bean>
Student.java
public void init() {
System.out.println("init");
}
public void destroy() {
System.out.println("destroy");
}
基于 xml 的自动装配
自动装配只针对于引用型属性,即手动装配的 ref=""
- 根据类型自动装配:将类型匹配的bean作为属性注入到另一个bean中。若IOC容器中有多个与目标bean类型一致的bean,Spring将无法判定哪个bean最合适该属性,所以不能执行自动装配
设有People.java 和 Address.java,People和Address为依赖关系
People有三个属性
private String id;
private String name;
private Address address;
<bean id="people" class="dao.People" autowire="byType">
<property name="id" value="0001"></property>
<property name="name" value="jinondo"></property>
</bean>
<bean id="address" class="dao.Address">
<property name="province" value="GuangDong"></property>
<property name="city" value="DG"></property>
</bean>
如果出现多个 class=“dao.Address” 的bean,byType的方式则会出错
- 根据名称自动装配:必须将目标bean的名称和属性名设置的完全相同。
<bean id="people" class="dao.People" autowire="byName">
<property name="id" value="0001"></property>
<property name="name" value="jinondo"></property>
</bean>
<bean id="address" class="dao.Address">
<property name="province" value="GuangDong"></property>
<property name="city" value="DG"></property>
</bean>
<bean id="address2" class="dao.Address">
<property name="province" value="GuangDong"></property>
<property name="city" value="ShanTou"></property>
</bean>
基于注解(Annotation)的装配
Repository,Controller,Service:
@Repository("userDaoImpl")
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("Dao: addUser");
}
}
@Controller
public class UserController {
public void handleUserInput() {
System.out.println("Controller: handle User Input");
}
}
@Service
public class UserService {
public void addUser() {
System.out.println("Service: add User");
}
}
xml 中的配置
<context:component-scan base-package="cyt"></context:component-scan>
bean id 默认为类名首字母小写,注解可以设置 bean 的 id,如
@Repository("userDaoImpl")
包含与排除
排除
<context:component-scan base-package="cyt">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
包含:只扫描选中的 bean!
注意排除应该配合父标签,即scan标签中的 use-default-filters 属性进行使用,即设置 use-default-filters="false"
<context:component-scan base-package="cyt" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
@Autowire工作机制
引用在基于注解装配时需要在引用前加上 @Autowire 注解
- Controller 中有 Service 的引用
@Repository("userDaoImpl")
@Controller
public class UserController {
@Autowired
private UserService service;
public void handleUserInput() {
System.out.println("Controller: handle User Input");
service.addUser();
}
}
- Service 里有 Dao 的引用
@Service
public class UserService {
@Autowired
private UserDao dao;
public void addUser() {
System.out.println("Service: add User");
dao.addUser();
}
}
Junit Test 测试
@Test
void test2() {
context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController userController = context.getBean("userController",UserController.class);
userController.handleUserInput();
}
由以上例子说明:@Autowired 注解对引用的装配属于 ByType 类型
如果 ByType 类型不能唯一找出一个,就会在 ByType 类型找出的多个bean基础上,进一步根据名字去找,例如 在@Repository(“userDaoImpl”) 时设置的 userDaoImpl。
如果不能按名字区别开2个或多个bean,则会出错!
@Qualifiter
@Qualifiter可以辅助@Autowire确定需要装配的Bean的id,在@Autowired找到多于两个的bean时,也可以用 @Qualifiter 直接设置要装配的 bean 的 id。
@Service
public class UserService {
@Autowired
@Qualifier("userDaoImpl")
private UserDao dao;
public void addUser() {
System.out.println("Service: add User");
dao.addUser();
}
}