spring详细进阶之IOC

目录:

一、使用配置文件

1.简单的依赖注入。

2.对象的生命周期:单例/原型。

3.依赖注入的两种方式:设值注入/构造注入。

4.对象工厂的延迟创建。

5.自动装配:byName/byType。

6.复杂对象的装配:list/map。

二、使用注解

7.javaweb的注解例子

工具:myeclipse 10

内容较多,对原理感兴趣的可以从第一部分开始,想快速开发的直接看注解部分

后面会附上源码,想参考的可以下载看看。

----------------------------------------------------------------分割线--------------------------------------------------------------------

1.简单的依赖注入

spring 框架提供了IOC(inversion of control)的一种代码实现方式:DI = 依赖注入(depency injection)。

综合运用了java的xml、面向对象、反射技术、工厂模式。

DI概念:类持有一个抽象接口,在运行期由他人注入实例来决定运行结果。

这里重点就是运行期,每次修改只需要改配置,不需要重新编译java文件,效率高。

另外构造时属性可以任意装配,灵活性大。

具体操作:

新建java project:Spring_1_IOC -> 在项目名右键选择MyEclipse -> 在右边出现的框中选择Add Spring Capabilities


next 只勾选Spring 3.0 Core Libraries -<MyEclipse-Library>


next->finish。完成之后如下图,自动生成了spring的配置文件


写个接口IFly.java

package utils;

public interface IFly {
	void fly();
}

写两个实现类作为飞行工具:Bird.java、Plane.java

package utils;

public class Bird implements IFly {
	@Override
	public void fly() {
		System.out.print("鸟在飞");
	}
}
package utils;

public class Bird implements IFly {

	@Override
	public void fly() {
		System.out.print("鸟在飞");
	}

}
写个超人类,超人可以使用飞行工具飞,也可以自己飞
package superman;
import utils.IFly;

public class Superman implements IFly{
	//传递飞行工具进来
	private IFly util;
	public IFly getUtil() {
		return util;
	}
	public void setUtil(IFly util) {
		this.util = util;
	}
	@Override
	public void fly() {
		if(util!=null){
			System.out.print("超人通过");
			util.fly(); System.out.println();
		}else 
			System.out.println("超人在飞");
	}
}
写个测试类Test.java,你会发现该类没有任何飞行工具类出现过。但是超人却可以使用飞行工具飞
package test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import superman.Superman;
import utils.IFly;

public class Test {
	public static void main(String [] args){
		BeanFactory bf = new ClassPathXmlApplicationContext("applicationContext.xml");		
		IFly superman = (Superman)bf.getBean("superman");
		superman.fly();
	}
}

在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"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">


	<bean id="plane" class="utils.Plane"></bean>
	<bean id="bird" class="utils.Bird"></bean>
	<bean id="superman" class="superman.Superman">
		<property name="util" ref="plane"></property><!-- ref对应id -->
	</bean>
</beans>
运行程序,控制台输出:
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
超人通过
鸟在飞
修改配置文件
<property name="util" ref="plane"></property>
运行程序,控制台输出:
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
超人通过飞机在飞

所以只要修改配置就可以实现超人的飞行工具,完全不用修改原代码。

2.对象的生命周期

singleton--单例。【默认】每次获取的对象都是同一个。

prototype--原型,每次获取都创建新的对象。

request--和request对象生命周期一致。获得响应后释放。针对web项目。(不演示)

session--和session对象生命周期一致。针对web项目。(不演示)

注意:误区:session不是关闭浏览器就结束生命周期,关闭浏览器只是jsessionid重建,服务器内存中的数据不会马上清理。

修改例1的plane.java ,为飞机添加属性:plane_name,tostring,get,set

package utils;

public class Plane implements IFly {
	private String plane_name;
	public String getPlane_name() {
		return plane_name;
	}
	public void setPlane_name(String plane_name) {
		this.plane_name = plane_name;
	}	
	@Override
	public void fly() {
		System.out.println("飞机在飞");
	}
	@Override
	public String toString() {
		return "Plane [plane_name=" + plane_name + "]";
	}
}
修改例1的applicationContext.xml,添加bean
<!-- 单例模式 scope=singleton -->
<bean id="plane_single" class="utils.Plane" scope="singleton">
	<property name="plane_name" value="歼-10"></property>
</bean>
<!-- 原型模式 scope=prototype -->
<bean id="plane_prototype" class="utils.Plane" scope="prototype">
	<property name="plane_name">
		<value>歼-10</value>
	</property>
</bean>
新建一个测试类TestPlane.java
package test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import utils.Plane;

public class TestPlane {
	public static void main(String [] args){
		BeanFactory bf = new ClassPathXmlApplicationContext("applicationContext.xml");
		Plane p1 = (Plane)bf.getBean("plane_single");
		Plane p2 = (Plane)bf.getBean("plane_single");
		System.out.println("----------------------单例--------------------------");
		System.out.println("两次的对象是不是同一个:"+(p1==p2));
		System.out.println("修改名字前的p1飞机:"+p1);
		System.out.println("修改名字前的p2飞机:"+p2);
		//我修改了p1的属性plane_name但是p2的属性plane_name也跟着变了
		p1.setPlane_name("歼-20");
		System.out.println("修改名字后的p1飞机:"+p1);
		System.out.println("修改名字后的p2飞机:"+p2);
		
		System.out.println("----------------------原型--------------------------");
		Plane p3 = (Plane)bf.getBean("plane_prototype");
		Plane p4 = (Plane)bf.getBean("plane_prototype");
		System.out.println("两次的对象是不是同一个:"+(p3==p4));
		System.out.println("修改名字前的p3飞机:"+p3);
		System.out.println("修改名字前的p4飞机:"+p4);
		//因为不是同一个对象,所以改了p3的属性,p4的属性不会变
		p3.setPlane_name("歼-20");
		System.out.println("修改名字后的p3飞机:"+p3);
		System.out.println("修改名字后的p4飞机:"+p4);
	}
}
控制台输出:
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
----------------------单例--------------------------
两次的对象是不是同一个:true
修改名字前的p1飞机:Plane [plane_name=歼-10]
修改名字前的p2飞机:Plane [plane_name=歼-10]
修改名字后的p1飞机:Plane [plane_name=歼-20]
修改名字后的p2飞机:Plane [plane_name=歼-20]
----------------------原型--------------------------
两次的对象是不是同一个:false
修改名字前的p3飞机:Plane [plane_name=歼-10]
修改名字前的p4飞机:Plane [plane_name=歼-10]
修改名字后的p3飞机:Plane [plane_name=歼-20]
修改名字后的p4飞机:Plane [plane_name=歼-10]

3.依赖注入的两种方式。

a.设置注入:本质上是通过反射调用setXxx方法。

b.构造注入:本质上是通过反射调用有参构造函数。

例1、例2用的就是设值注入,现在演示下构造注入:

修改例2的Superman.java类,添加有参构造函数和无参构造函数:

package superman;
import utils.IFly;

public class Superman implements IFly{
	//有参构造函数
	public Superman(IFly util) {
		super();
		this.util = util;
	}
	//无参构造函数
	public Superman() {
		super();
	}
	//传递飞行工具进来
	private IFly util;
	public IFly getUtil() {
		return util;
	}
	public void setUtil(IFly util) {
		this.util = util;
	}
	@Override
	public void fly() {
		if(util!=null){
			System.out.println("超人通过");
			util.fly();
		}else 
			System.out.println("超人在飞");
	}
}

修改例2的applicationContext.xml,添加bean

<!-- 构造注入 -->
<bean id="superman_constructor" class="superman.Superman">
	<constructor-arg index="0">
		<ref bean="bird"/>
	</constructor-arg>
</bean>

修改例2的Test.java

package test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import superman.Superman;
import utils.IFly;

public class Test {
	public static void main(String [] args){
		BeanFactory bf = new ClassPathXmlApplicationContext("applicationContext.xml");		
		IFly superman = (Superman)bf.getBean("superman");
		superman.fly();
		//构造注入
		IFly superman2 = (Superman)bf.getBean("superman_constructor");
		superman2.fly();
	}
}

控制台输出:

log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
超人通过飞机在飞
超人通过鸟在飞

4.对象工厂的延迟创建

lazy-init= true. 默认是false,在创建工厂时自动创建。

修改例3的Bird.java , 添加bird_name属性和get,set,无参构造函数,有参构造函数

package utils;

public class Bird implements IFly {
	private String bird_name;
	public String getBird_name() {
		return bird_name;
	}
	public void setBird_name(String bird_name) {
		this.bird_name = bird_name;
	}
	public Bird() {
		super();
	}
	public Bird(String bird_name) {
		super();
		if(bird_name!=null)System.out.print(bird_name);
		System.out.println("鸟被创建了");
		this.bird_name = bird_name;
	}
	@Override
	public void fly() {
		if(bird_name!=null)System.out.print(bird_name);
		System.out.print("鸟在飞");
	}

}
修改例3的applicationContext.xml,添加bean
<!-- 对象工厂的延迟创建 -->
<bean id="bird_lazy_true" class="utils.Bird" lazy-init="true">
	<constructor-arg name="bird_name" value="黄雀"></constructor-arg>
</bean>
<bean id="bird_lazy_false" class="utils.Bird" lazy-init="false">
	<constructor-arg index="0">
		<value>杜鹃</value>
	</constructor-arg>
</bean>
<!-- lazy-init作用:如果对应的类需要做很多初始化工作且与其他类关联众多,那么建议使用默认lazy-init=false得形式
	另外,如果对应的类没有初始化的工作,且相对独立,那么建议使用延迟创建的配置lazy-init=true
 -->
写测试类TestBird.java
package test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import utils.Bird;

public class TestBird {
	public static void main(String [] args){
		BeanFactory bf = new ClassPathXmlApplicationContext("applicationContext.xml");
		Bird b1 = (Bird)bf.getBean("bird_lazy_true");
		Bird b2 = (Bird)bf.getBean("bird_lazy_false");
		//因为b1是懒加载,所以b1是在被使用的时候才创建对象,所以b2的fly方法会比较早被调用
		b1.fly();
		System.out.println();
		b2.fly();
	}
}
控制台输出:
杜鹃鸟被创建了
黄雀鸟被创建了
黄雀鸟在飞
杜鹃鸟在飞

5.自动装配

no:默认,不自动装配

byName:靠属性名和bean的ID进行识别

byType:靠属性类型和bean的class进行识别。要保证 符合该type的bean唯一,否则会报错。

constructor:靠构造函数入参的属性名进行识别本质上也是。

在例4的项目中src下新建applicationContext2.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"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
	 <!-- 自动装配之byName -->
	 <bean id="util" class="utils.Plane">
		<property name="plane_name" value="歼-10"></property>
	</bean>
	<!-- 因为Superman.java里面有个属性名是util,所以byName会查找id=util的bean -->
	<bean id="superman" class="superman.Superman" autowire="byName"></bean>
	
	<!-- 自动装配之byType -->
	<!-- 因为superwoman里面有个superman属性类型是superman.Superman,
		所以她会自动匹配该配置文件里面的class为superman.Superman的bean
		如果有多个bean的class为superman.Superman则报错 -->
	<bean id="superwoman" class="superman.Superwoman" autowire="byType"></bean>
</beans>
新建superwoman.java
package superman;
import utils.IFly;

public class Superwoman implements IFly{
	
	private Superman superman;
	public Superman getSuperman() {
		return superman;
	}
	public void setSuperman(Superman superman) {
		this.superman = superman;
	}
	@Override
	public void fly() {
		if(superman!=null){
			System.out.print("女超人和");
			superman.fly();
			System.out.println();
		}else 
			System.out.println("女超人在飞");
	}
}
新建TestAuto.java
package test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import superman.Superman;
import superman.Superwoman;

public class TestAuto {
	public static void main(String[] args) {
		BeanFactory bf = new ClassPathXmlApplicationContext("applicationContext2.xml");
		//自动装配之byName
		Superman superman = (Superman) bf.getBean("superman");
		superman.fly();
		//自动装配之byType
		Superwoman superwoman = (Superwoman)bf.getBean("superwoman");
		superwoman.fly();
	}
}
控制台输出:
超人通过飞机在飞
女超人和超人通过飞机在飞
源码: Spring_1_IOC

6.复杂对象的装配

项目内容有点多了,所以新建一个java project:Spring_2_IOC

Spring_2_IOC -> 在项目名右键选择MyEclipse -> 在右边出现的框中选择Add Spring Capabilities


演示一下list的例子。

NBA.java

package nba;
import java.util.List;

public class NBA {
	private String foundTime;  //成立时间
	private String director;  //主席
	private List<NBATeam> teams;
	public String getFoundTime() {
		return foundTime;
	}
	public void setFoundTime(String foundTime) {
		this.foundTime = foundTime;
	}
	public String getDirector() {
		return director;
	}
	public void setDirector(String director) {
		this.director = director;
	}
	public List<NBATeam> getTeams() {
		return teams;
	}
	public void setTeams(List<NBATeam> teams) {
		this.teams = teams;
	}
	@Override
	public String toString() {
		return "NBA [foundTime=" + foundTime + ", director=" + director
				+ ", 球队个数=" + teams.size() + "]";
	}
}
NBATeam.java

package nba;
import java.util.List;

public class NBATeam {
	private String teamname;
	private String superstar; 
	private List<String> players;
	public String getTeamname() {
		return teamname;
	}
	public void setTeamname(String teamname) {
		this.teamname = teamname;
	}
	public String getSuperstar() {
		return superstar;
	}
	public void setSuperstar(String superstar) {
		this.superstar = superstar;
	}
	public List<String> getPlayers() {
		return players;
	}
	public void setPlayers(List<String> players) {
		this.players = players;
	}
	@Override
	public String toString() {
		return "NBATeam [teamname=" + teamname + ", superstar=" + superstar
				+ ", players=" + players + "]";
	}
}
Test.java

package nba;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

	
	public static void main(String[] args) {
		
		BeanFactory fac = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		NBA nba = (NBA)fac.getBean("nba");
		System.out.println(nba);
		for(NBATeam team:nba.getTeams()){
			System.out.println(team);
		}
	}
}

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" xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	<!-- list -->
	<bean id="nba" class="nba.NBA" autowire="byType">
		<property name="foundTime" value="1946-6-6"></property>
		<property name="director" value="萧华"></property>
		<!-- 这边如果要接收的是list,那么即使是byType也支持多个类型的bean -->

	</bean>
	<bean class="nba.NBATeam">
		<property name="teamname" value="火箭队"></property>
		<property name="superstar" value="哈登"></property>
		<property name="players">
			<list>
				<value>保罗</value>
				<value>罗琦</value>
			</list>
		</property>
	</bean>
	<bean class="nba.NBATeam">
		<property name="teamname" value="湖人队"></property>
		<property name="superstar" value="科比"></property>
		<property name="players">
			<list>
				<value>兰德尔</value>
				<value>拉塞尔</value>
			</list>
		</property>
	</bean>
</beans>
控制台输出:

NBA [foundTime=1946-6-6, director=萧华, 球队个数=2]
NBATeam [teamname=火箭队, superstar=哈登, players=[保罗, 罗琦]]
NBATeam [teamname=湖人队, superstar=科比, players=[兰德尔, 拉塞尔]]

map的例子

SportsScore.java

package sport;
import java.util.Map;
class Athlete{
	private String name;
	private String age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAge() {
		return age;
	}
	public void setAge(String age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Athlete [name=" + name + ", age=" + age + "]";
	}
}
public class SportsScore {
	private String nation;
	private String year;
	private Map<String,Integer> score;
	private Map<String,Athlete> athletes;
	public String getNation() {
		return nation;
	}
	public void setNation(String nation) {
		this.nation = nation;
	}
	public String getYear() {
		return year;
	}
	public void setYear(String year) {
		this.year = year;
	}
	public Map<String, Integer> getScore() {
		return score;
	}
	public void setScore(Map<String, Integer> score) {
		this.score = score;
	}
	
	public Map<String, Athlete> getAthletes() {
		return athletes;
	}
	public void setAthletes(Map<String, Athlete> athletes) {
		this.athletes = athletes;
	}
	@Override
	public String toString() {
		return "SportsScore [nation=" + nation + ", year=" + year + ", score="
				+ score + ", athletes=" + athletes + "]";
	}
}

Test.java

package sport;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
	public static void main(String[] args) {
		BeanFactory fac = new ClassPathXmlApplicationContext("applicationContext.xml");
		SportsScore ss = (SportsScore)fac.getBean("sportsscore");
		System.out.println(ss);
	}
}

在applicationContext.xml添加bean

<!-- map -->
	<bean id="sportsscore" class="sport.SportsScore">
		<property name="year" value="2016"></property>
		<property name="nation" value="中国"></property>
		<property name="score">
			<map>
				<entry>
					<key>
						<value>金牌</value>
					</key>
					<value>25</value>
				</entry>
				<entry>
					<key>
						<value>银牌</value>
					</key>
					<value>20</value>
				</entry>
				<entry>
					<key>
						<value>铜牌</value>
					</key>
					<value>30</value>
				</entry>
			</map>
		</property>
		<property name="athletes">
			<map>
				<entry>
					<key><value>乒乓球</value></key>
					<bean class="sport.Athlete">
						<property name="name" value="马龙"></property>
						<property name="age" value="23"></property>
					</bean>
				</entry>
				<entry>
					<key><value>羽毛球</value></key>
					<bean class="sport.Athlete">
						<property name="name" value="谌龙"></property>
						<property name="age" value="23"></property>
					</bean>
				</entry>
			</map>
		</property>
	</bean>
控制台输出:

SportsScore [nation=中国, year=2016, score={金牌=25, 银牌=20, 铜牌=30}, athletes={乒乓球=Athlete [name=马龙, age=23], 羽毛球=Athlete [name=谌龙, age=23]}]

7.javaweb的注解例子

我就不重复造轮子了,参考下别人的博客:Spring IOC 常用注解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值