1.spring容器的作用:
spring容器本质是一个上下文,是我们编写的应用的环境。为什么要使用这个上下文?传统上我们写a调用b的f方法肯定是在a类的方法中new一个b的对象,在用b的f方法,这样写的问题主要是增加了a,b的耦合,具体体现在,a本来是调用b的方法,但是它必须事先new一个b,new一个b意味着要得知b的另一个接口(本来只要知道f),现在又要知道b的创建接口(构造方法),潜在的问题是如果b的构造接口发生改变,那么会影响到a的代码。比如原来是构造方法,现在改成了工厂方法。
那么如何改进呢?我们不让a来new一个b,而是为这个调用的情景创建一个上下文,在上下文中完成调用。那么就会成为下面的:
class c{
function f(){
A a = new A();
B b = new B();
a.setB(b);
a.ff();
}
}
这不是标准的java代码。上下文便是C类,c类负责创建实例,并且组装,把b的实例给了a,这样a只管用b就行,不用在担心b的创建了。最终把耦合性带到了C类中。
当然,不足之处在于上下文C还得由我们在掌控。Spring容器所做的工作与C类相同,只不过它要复杂的多,它便是为我们的应用创建了一个不用我们维护的上下文(当然能需要初始化容器内的实例了,其它的是衣来伸手饭来张口。有要用的就拿),在容器内部缓存了很多的实例,我们要用那个,只需要调用这个实例的方法即可,并不用关心创建过程。
2.加载:
在web。xml文件中,通过、
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
listener来初始化容器,ContextLoaderListener是一个类,创建spring容器,这个过程挺复杂,《spring技术内幕》一书讲的很详细。
3.bean:
默认的spring容器配置文件是applicationContext.xml,实际上是定义了容器内要存储的对象。
每一个对象都用bean标签定义。
<?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-3.0.xsd"
xmlns:p="http://www.springframework.org/schema/p">
<!-- 定义一个bean -->
<bean id="bean1" class="com.model.Person">
<!-- 为bean注入属性或者依赖 -->
<!-- 如果是基本类型,用value标签 -->
<property name="age"><value>12</value></property>
<property name="name"><value>liyao</value></property>
<!-- 如果是引用类型,用ref标签 -->
<property name="address"><ref bean="bean2"></ref></property>
</bean>
<bean id="bean2" class="com.model.Address">
<!-- 为bean注入属性或者依赖 -->
<property name="address"><value>白云小区</value></property>
</bean>
<!-- 使用p命名空间 -->
<bean id="bean3" class="com.model.Address"
p:address="狄村"/>
<!-- bean scope -->
<bean id="bean4" class="com.model.Car" scope="prototype">
</bean>
<bean id="bean5" class="com.model.Car">
</bean>
</beans>
这便是一个例子。
最上面的xmlns声明一个xml文档的命名空间,比如要用p:xxx就要提前声明p命名空间,mvc:也同理。xsi命名空间是指定了其他命名空间的文档。
*每一个bean的id必须唯一,作为标识;
*注入bean的属性时,可以用property标签定义,这是set注入方式,比较推荐着一种。也可以引入p标签,定义起来更方便,需要命名空间。
*bean有一个scope如果是prototype,每次都会new一个新的,如果是单例的,就返回相同的对象,默认单例。
以上是使用xml方式配置bean。
更方便的是使用注解方式,需要在spring-mvc配置文件中加入扫描包的启动注解的配置。
可以用@Component来定一个一个bean。为了更好的理解有@Service@Controller@Resource三个标签,分别标识service层组件,controller组件和dao组件。
如果要使用一个bean,那么可以在声明的上方用@Autowired,返回spring容器中唯一的这个类型的实例,如果有多个,必须再加:
@Autowired
@Qualifier("dao")
只用一个都不行。
使用注解的方式更加方便,加快开发进度,但是可能可读性不如xml方式。
package com.test;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.beans.BigCar;
import com.model.Address;
import com.model.Car;
import com.model.Person;
@Controller
public class TestController {
@Qualifier("bean5")
private Car car;
@Autowired
BigCar gc;
@RequestMapping(value="/index")
public String index(HttpServletRequest request){
ServletContext servletContext = request.getServletContext();
String path = servletContext.getRealPath("/WEB-INF/config/");
System.out.println(path);
ApplicationContext a = new FileSystemXmlApplicationContext(path+"/spring.xml");
Address address = (Address) a.getBean("bean2");
System.out.println(address.getAddress());
Person person = (Person) a.getBean("bean1");
System.out.println(person.getAge());
System.out.println(person.getName());
Address address2 = (Address) a.getBean("bean3");
System.out.println(address2.getAddress());
Car car1 = (Car) a.getBean("bean4");
System.out.println(car1.getCount());
Car car2 = (Car) a.getBean("bean5");
System.out.println(car2.getCount());
//BigCar gc = (BigCar) a.getBean("bean6");
//System.out.println(gc.getPerson().getAddress());
gc.getClass();
System.out.println(gc.getDao());
System.out.println(gc.getAddress());
return "index";
}
}