经过上篇文章大概知道ioc、DI的概念了,下面咱们详细介绍一下java
IOC经过上文的介绍做用是控制建立对象的解释权,咱们把代码从新看一下mysql
//User.java public class User { private String username; private String password; /** * 省略有参无参构造器,getter/setter方法 */ }
咱们也不建立dao、service类了,直接就用这个User类来测试spring
配置文件:applicationContext.xmlsql
<?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"> <!-- id:建立的bean的惟一标识,做用是区分其它的bean class:建立的对象的全限定名(包名+类名) --> <bean id="user" class="com.ty.bean.User"></bean> </beans>
//测试文件 public class MyTest { ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); @Test public void test1(){ User user = (User) context.getBean("user"); System.out.println(user); } }
这是IOC建立对象的第一种方式即经过bean的id获取IOC容器中的对象:context.bean("配置文件bean中的id")数据库
还有另外两种方式 :session
@Test public void test2(){ User user = context.getBean(User.class); System.out.println(user); }
这种注入方法有劣势,即:配置文件中有多个同类型的bean(即class重复)时,注入对象就会报错,例如:app
<?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"> <!-- id:建立的bean的惟一标识,做用是区分其它的bean class:建立的对象的全限定名(包名+类名) --> <bean id="user" class="com.ty.bean.User"></bean> <bean id="use2" class="com.ty.bean.User"></bean> </beans>
再接着运行测试文件的时候就会报NoUniqueBeanDefinitionException异常ide
@Test public void test3(){ User user = context.getBean("user",User.class); System.out.println(user); }
光建立对象没用,最重要的仍是为对象赋值,咱们说过DI是IOC的实现,DI更能经过代码体现出来,接下开咱们依次介绍几种赋值方式post
<bean id="user" class="com.ty.bean.User"> <!-- property:表示属性注入 name:属性的名字,实际上是常规bean中set以后的名字(首字母小写) value:属性值 --> <property name="username" value="root"></property> <property name="password" value="123456"></property> </bean>
public class Address { private String city; /** * 省略有参无参构造器,getter/setter方法 */ } public class User { private String username; private String password; private String[] hobby; private Address address; private List list; private Set set; private Map map; private Properties properties; /** * 省略有参无参构造器,getter/setter/toString方法 */ }
<!-- private String[] hobby --> <property name="hobby"> <array> <value>吃饭</value> <value>看电影</value> <value>打游戏</value> <!-- 表示赋空值,能够起占位做用--> <null></null> </array> </property> <!--private Address address- 能够有2种注入方式,一种方式在property标签嵌套一个bean--> <!-- <property name="address">--> <!-- <bean class="com.ty.bean.Address">--> <!-- <property name="city" value="大连"></property>--> <!-- </bean>--> <!-- </property>--> <!--ref:引用的bean的id--> <property name="address" ref="address"></property> <!-- private List list--> <property name="list"> <list> <value>a</value> <value>b</value> <value>c</value> </list> </property> <!-- private Set set--> <property name="set"> <set> <value>redio</value> <value>book</value> <value>game</value> </set> </property> <!-- private Map map--> <property name="map"> <map> <entry key="1" value="北京"></entry> <entry key="2" value="上海"></entry> <entry key="3" value-ref="address"></entry> </map> </property> <!-- private Properties properties--> <property name="properties"> <props> <prop key="username">root</prop> <prop key="password">root</prop> </props> </property> </bean> <bean id="address" class="com.ty.bean.Address"> <property name="city" value="大连"></property> </bean>
List,Set,Map,Properties中还有一种注入方式,即util命名方式,主要的做用:方便别人引用测试
<!-- private List list--> <property name="list" ref="mylist"></property> <!-- private Set set--> <property name="set" ref="myset"></property> <!-- private Map map--> <property name="map" ref="mymap"></property> <!-- private Properties properties--> <property name="properties" ref="myproperties"></property> </bean> <util:list id="mylist"> <list> <value>a</value> <value>b</value> <value>c</value> </list> </util:list> <util:set id="myset"> <set> <value>redio</value> <value>book</value> <value>game</value> </set> </util:set> <util:map id="mymap"> <entry key="1" value="北京"></entry> <entry key="2" value="上海"></entry> <entry key="3" value-ref="address"></entry> </util:map> <util:properties id="myproperties"> <prop key="username">root</prop> <prop key="password">root</prop> </util:properties>
除了上方util命名空间方式以外搭配着还有一个P命名空间
<bean id="user2" class="com.ty.bean.User" p:username="root" p:password="123456" p:address-ref="address" p:list-ref="mylist"></bean>
能够按照必定规则进行装配注入,不用具体指定为某个属性赋值,在工厂中查找一个bean,为属性注入属性值。
<bean id="address" class="com.ty.bean.Address"> <property name="city" value="上海"></property> </bean> <bean id="person" class="com.ty.bean.Person" autowire="byName"></bean>
byName:按照bean的id进行装配
byType:按照bean的类型来进行注入,可是若是有多个相同类型,就会报错,不知道选择哪个具体的类型
public class User { private String username; private String password; /** * 省略有参无参构造器,getter/setter方法 */ }
<bean id="user3" class="com.ty.bean.User"> <!--构造注入的constructor-arg标签里还有几个属性 name:形参列表的名称 value:实参的值 type:参数类型 index:参数索引,从0开始 --> <constructor-arg name="username" value="root"></constructor-arg> <constructor-arg name="password" value="123456"></constructor-arg> </bean>
属性注入有P命名空间,构造器注入有C命名空间
<bean id="user4" class="com.ty.bean.User" c:username="root" c:password="123456"></bean>
<bean id="person" class="com.ty.bean.Person" autowire="constructor"></bean>
<bean id="parent" class="com.ty.bean.User"> <property name="username" value="root"></property> </bean> <!--parent:指定继承的bean信息--> <bean id="son" class="com.ty.bean.User" parent="parent"></bean>
这个是在继承关系的父bean里添加abstract属性,这个做用就是该bean是否能实例化
<bean id="parent" class="com.ty.bean.User" abstract="true"> <property name="username" value="root"></property> </bean>
这个就是bean的前后建立顺序,depends-on依赖哪一个bean就谁先建立谁,而后再建立本对象
<bean id="user5" class="com.ty.bean.User" depends-on="address"></bean> <bean id="address" class="com.ty.bean.Address"> <property name="city" value="大连"></property> </bean>
经过scope属性指定当前bean的做用域,有四个值
singleton:单例模式,从IOC容器中获取的都是同一个对象,默认的做用域
prototype:多例模式,从IOC容器中获取的对象每次都是新建立
request:每次发送请求都会有一个新的对象
session:每一次会话都会有一个新的对象
<bean id="user5" class="com.ty.bean.User" scope="singleton"></bean>
ps:singleton做用域:每次在建立IOC容器完成以前此对象已经建立完成,即:
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
prototype做用域:每次是在须要用到此对象的时候才会建立,即
User user = (User) context.getBean("user");
工厂自己不须要建立对象,可是能够经过静态方法调用,对象=工厂类.静态工厂方法名();
public class PersonStaticFactory { public static Person getInstance(String name){ Person person=new Person(); person.setId(1001); person.setAge(18); person.setName(name); return person; } }
<!--静态工厂:类名.静态方法()--> <bean id="person" class="com.ty.factory.PersonStaticFactory" factory-method="getInstance"> <constructor-arg value="jack"></constructor-arg> </bean>
工厂自己须要建立对象,工厂类 工厂对象=new 工厂类;工厂对象.get对象名();
public class PersonInstanceFactory { public Person getInstance(String name){ Person person=new Person(); person.setId(1001); person.setAge(18); person.setName(name); return person; } }
<!--实例工厂:先建立工厂实例,而后调用工厂实例的方法 factory-bean:表示具体工厂类的实例 factory-method:表示具体工厂实例的方法 --> <bean id="factory" class="com.ty.factory.PersonInstanceFactory"></bean> <bean id="person" class="com.ty.bean.Person" factory-bean="factory" factory-method="getInstance"> <constructor-arg value="jack"></constructor-arg> </bean>
FactoryBean是Spring规定的一个接口,当前接口的实现类,Spring都会将其做为一个工厂,可是在ioc容器启动的时候不会建立实例,只有在使用的时候才会建立对象
public class MyFactoryBean implements FactoryBean { /** * 此方式是spring建立bean方式的一种补充,用户能够按照需求建立对象, 建立的对象交由spring IOC容器来进行管理,不管是不是单例,都是在用到的时候才会建立该对象,不用该对象不会建立 */ @Override public Person getObject() throws Exception { //建立的对象 Person person=new Person(); person.setId(1001); person.setName("jack"); person.setAge(20); return person; } @Override public Class<?> getObjectType() { //返回对象的类型 return Person.class; } @Override public boolean isSingleton() { //是否单例 return true; } }
<bean id="factoryBean" class="com.ty.factory.MyFactoryBean"></bean>
在对象建立完成以后会调用初始化方法
实现InitializingBean接口
//实现这个方法,完成初始化操做 @Override public void afterPropertiesSet() throws Exception { System.out.println("afterPropertiesSet"); }
对象中提供一个普通的方法同时配置Spring配置文件:
public void init(){ System.out.println("init"); }
<bean id="p" class="com.ty.bean.Person" init-method="init"></bean>
顺序:对象的注入-》InitializingBean-》普通init-method
@Override public void destroy() throws Exception { System.out.println("destory"); }
public void mydestory(){ System.out.println("mydestory"); }
<bean id="p" class="com.ty.bean.Person" scope="prototype" init-method="init" destroy-method="mydestory"> <property name="id" value="1001"></property> </bean>
销毁方法只会在scope="singleton"时才会调用,并且须要对象关闭,例如:context.close()
spring中包含一个BeanPostProcessor的接口,能够在bean的初始化方法的先后调用该方法,若是配置了初始化方法的前置和后置处理器,不管是否包含初始化方法,都会进行调用
public class MyBeanPostProcessor implements BeanPostProcessor { //对象初始化以前执行 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization"+beanName); return bean; } //对象初始化对象以后运行 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization"+beanName); return bean; } }
<bean class="com.ty.bean.MyBeanPostProcessor"></bean> <bean id="p" class="com.ty.bean.Person" scope="prototype" init-method="init" destroy-method="mydestory"> <property name="id" value="1001"></property> </bean>
就是把Spring配置文件中须要常常修改的字符串信息,转移到一个更小的配置文件中,方便后期的维护
例如:数据库链接
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <property name="url" value="${jdbc.url}"></property> <property name="driverClassName" value="${jdbc.driverClassName}"></property> </bean>
jdbc.username=root jdbc.password=root jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/demo
//测试 @Test public void test11() throws SQLException { ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); DruidDataSource dataSource = context.getBean("dataSource", DruidDataSource.class); System.out.println(dataSource); System.out.println(dataSource.getConnection()); }