一个类中,尽量不和其它的类产生耦合(即不使用new)的方法:1) 使用工厂模式。直接从工厂中得到实例;
2) 控制反转(IOC)。应用本身不负责依赖对象的创建和维护,由外部容器负责。控制权利由应用转移到了外部容器,控制权的转移就是所谓反转; 依赖注入(DI)。在运行期间,由外部容器动态地将依赖对象注入到组件中。
面向切面编程(AOP):通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的技术。主要功能:日志记录、性能统计、安全控制、事务处理、异常处理等。使用JDK的动态代理可以实现AOP。
Spring的IOC容器包含并管理应用对象的配置和生命周期。可以配置每个bean如何被创建,可以配置每个bean是只有一个实例,还是每次需要时都生成一个新的实例,以及它们是如何相互关联的。
Spring的优点:1) 降低组件之间的耦合度,实现解耦;
2) 容器提供单例模式支持;
3) AOP技术;
4) 持久化服务;
5) 对主流的框架提供了集成支持。
BeanFactory和ApplicationContext
区别:a) ApplicationContext是BeanFactory的子接口;
b) ApplicationContext的功能要多于BeanFactory,如它可以加载外部的资源文件、可以自动进行AOP切面、可以识别自动代理的的类、可以识别用于监听Bean创建的类等。
ApplicationContext是一个接口,有多个实现类,我们在使用时就是用的他的某个实现类:a) ClassPathXmlApplicationContext(读取类路径中的资源)
b) FileSystemXmlApplicationContext(读取指定路径的资源,推荐使用绝对路径)
c) XmlWebApplicationContext(在Web应用中使用)
使用类ApplicationContext获取Bean:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"cn/itcast/b_springhelloworld/applicationContext.xml"); //获取配置文件
UserServiceImpl userServiceImpl = (UserServiceImpl) applicationContext.getBean(
"userService"); //从配置文件中获得对象
实例化bean的三种方式
a) 使用类构造器实例化
b) 使用静态工厂方法实例化
工厂类:
public class StaticDaoFactory {
// 方法必须声明为static的
public static Object createUserDaoInstance() {
System.out.println("StaticDaoFactory.createUserDaoInstance()");
return new UserDaoImpl();
}
}
c) 使用实例化的工厂对象中的方法实例化(首先创建工厂bean,再调用工厂中创建实例的方法得到实例对象)
工厂类:
public class SimpleDaoFactory {
// 方法不能声明为static的
public static Object createUserDaoInstance() {
System.out.println("SimpleDaoFactory.createUserDaoInstance()");
return new UserDaoImpl();
}
}
a) singleton(单例,默认值);饿汉式(默认值,加载类时就初始化实例),懒汉式(lazy-init=”true”,第一次调用getInstance()时获取bean时才生成实例)。对所有bean应用延迟初始化,在根节点beans中设置属性default-lazy-init=”true”;
b) prototype(原型,每次获取的都是新对象);
c) 其他作用域。
依赖注入的配置方式
一、通过setter方法注入:
二、通过构造器注入:
或是:
注入普通属性(基本类型或者String类型):
注入null值
3.3.2依赖对象的注入
方式一:
定义bean时不分先后,Spring会自动处理他们之间的依赖关系,以决定先创建谁。
方式二:使用内部bean,因为没有id或name,所以该bean不能被其他bean使用
3.3.3注入集合属性
一、创建类
public class User {
private String name;
// 集合属性要定义为接口类型
// 集合类型可以不初始化,因为会注入一个新的集合对象
// 集合最好指定强类型,以便Spring转型,如果未指定,就会是String型的值
// 如果没有指定强类型,也可以在配置时指定:
//
10
private Set
addressSet = new HashSet
();
private Set
numberSet;
private List
addressList;
private String[] addressArray;
private Map
addressCodeMap; private Properties userProperties; public void printInfo() { System.out.println("name = " + name); System.out.println("addressSet = " + addressSet); System.out.println("numberSet = " + numberSet); System.out.println("addressList = " + addressList); System.out.println("addressArray = " + Arrays.toString(addressArray)); System.out.println("addressCodeMap = " + addressCodeMap); System.out.println("userProperties = " + userProperties); } // getter与setter略 } 二、配置
上地东路27号
上地东路28号
1
2
上地东路27号
上地东路28号
hello
world
依赖注入的注解方式
a) 引入context命名空间;
b) 在配置文件中添加context:component-scan标签。
xmlns:context="http://www.springframework.org/schema/context"
<!-- 设置为自动扫描与装配bean,扫描指定包及其所有下级包中的类,可以写多个,之间用英文的逗号隔开 -->
<context:component-scan base-package="cn.itcast"></context:component-scan>
组件自动扫描机制,它可以在类路径底下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入进spring容器中管理。它的作用和在xml文件中使用bean节点配置组件是一样的。
功能介绍:
@Service用于标注业务层组件
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注
@Scope用于指定当前bean的作用域
@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。如果没有指定name属性,并且按照默认的名称找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。
@Resource是用于注入依赖的bean:
可以通过name属性指定所需要的bean的名称,如果找不着,则抛异常。或可以通过type属性指定所需要的bean的类型,如果只有一个bean匹配这个类型,则就是他它
@Resource(name="personDao")
private PersonDao personDao;;//用于字段上
@Resource(name="personDao")
public void setPersonDao(PersonDao personDao) {//用于属性的set方法上
this.personDao = personDao;
}
后一种相当于xml配置文件中的
<property name=“personDao" ref="personDao" />
在applicationContext.xml中配置bean时,可以指定abstract属性,其默认为false,如果为true,则容器就不会创建这个类的实例,这时就可以不指定class属性。通常用于抽取公共的配置到一个不对应具体类的bean定义,此bean只用于被其他bean定义继承。
在声明bean时可以指定parent属性,其值为另一个bean的id或是name的值,表示把parent中的定义继承过来,就像自己有这些定义一样。注意:这只是在配置时方便,与实际的类结构无关。在父Bean中定义的属性必须要在子Bean中出现。如果子Bean中没有定义相关属性,将会导致容器初始化失败。
引入外部资源
classpath:cn/itcast/l_di_placeholder/a.properties
classpath:cn/itcast/l_di_placeholder/b.properties
二、使用
加载外部的资源文件
要使用Context命名空间
a) 先找properties中的配置,如果找到就返回;
b) 如果第一步没找到,就从system proeprties中查找(使用System.getProperty(String key) 的值),如果找到就返回;
c) 如果还没找到,就抛异常,说找不到这个变量的值。