目录:
一、使用配置文件
二、使用注解
工具: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();
}
}
控制台输出:
超人通过飞机在飞
女超人和超人通过飞机在飞
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 常用注解