ioc 和aop是spring的核心
spring整合其他技术,例如jdbc,mybtis,hibernate,struts等。
spring ioc应用
a。管理对象
创建,初始化,释放资源,销毁
b。维护对象关系
c。搭建SpringIOC开发环境,引入jar包,在src添加applicationContext.xml
spring模块需要的jar包:
ioc:commons-logging,spring-beans,spring-context,spring-core,spring-expression
aop:aopaliance,aspectjweaver,spring-aop,spring-aspects
dao:spring-jdbc,spring-tx
dbcp:commons-collections,commons-dbcp,commons-pool
json:jackson-annotation,jackson-core,jackson-databind
webmvc:spring-web,spring-webmvc
servlet用到的json包(springmvc不用这些):commons-beanutil,commons-collections,commons-lang,commons-logging,ezmorph,json-lib
例子,管理对象的三种方式:
java代码:
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Calendar c1=ac.getBean("c1",Calendar.class);
Calendar c2=ac.getBean("c2",Calendar.class);
Date date=ac.getBean("date",Date.class);
System.out.println(c2);
applicationContext.xml:
<!-- 采用new GregorianCalendar(),构造方法 -->
<bean id="c1" class="java.util.GregorianCalendar"></bean>
<!-- 采用Calendar.getInstance(),静态工厂方法 -->
<bean id="c2" class="java.util.Calendar" factory-method="getInstance"></bean>
<!-- 采用c2.getTime(),对象工厂方法 -->
<bean id="date" factory-bean="c2" factory-method="getTime"></bean>
2.Spring创建Bean对象的控制
a.控制对象创建方式(使用范围)
在<bean> 元素中使用scope属性控制。scope可以支持singleton或prototype。默认值是singleton单例模式
<bean scope="singleton">该组件在spring容器里只有一个bean对象。
<bean scope="prototype">该组件每次ac.getBean("id")返回不同的bean对象。
b。指定对象初始化操作。
假设对象里有个init()方法,public void init(){xxxxx};让t1这个实例对象一创建完,自动调用init方法。
<bean id="t1" class="org.alexhe.bean.Test" init-method="init"></bean>
c。指定对象销毁时操作:(比较少用)并需要满足条件才有效:1,组件为单例模式。2,调用AbstractApplicationContext容器对象的close()方法
假设对象里有个mydestroy方法,public void mydestroy(){xxxxx};让t1这个实例对象一旦销毁,自动调用mydestroy方法。
<bean id="t1" class="org.alexhe.bean.Test" destroy-method="mydestroy"></bean>
d。控制单例对象创建时机。 不在容器一开始建立时创建对象,而是在ac.getBean("t1",Test.class)时才创建对象。
<bean id="t1" class="org.alexhe.bean.Test" destroy-method="mydestroy" lazy-init="true"></bean>
ioc信息set注入,管理关系,set注入和构造器注入:
java类:
public class Computer {
private String cpu;
private String hdd;
private String mainboard;
public void show(){
System.out.println("cpu:"+cpu);
System.out.println("hdd:"+hdd);
System.out.println("mainboard:"+mainboard);
}
//省略get set方法
}
xml:
<bean id="p1" class="org.alexhe.bean.Computer">
<!-- 信息set注入 -->
<property name="cpu" value="骁龙"></property>
<property name="hdd" value="希捷"></property>
<property name="mainboard" value="华硕"></property>
</bean>
测试类:
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Computer c=ac.getBean("p1",Computer.class);
c.show();
构造器注入:
javaBean:
public Computer(String cpu,String hdd){
this.cpu=cpu;
this.hdd=hdd;
}
xml:
<bean id="p2" class="org.alexhe.bean.Computer">
<!-- 构造器注入 -->
<constructor-arg index="0" value="高通"></constructor-arg>
<constructor-arg index="1" value="2G"></constructor-arg>
</bean>
测试类:
Computer c=ac.getBean("p1",Computer.class);
c.show();
组件注入:student需要一个computer组件
javaBean:
public class Student {
private Computer c;
public void show(){
c.show();
}
public Computer getC() {
return c;
}
public void setC(Computer c) {
this.c = c;
}
}
xml:
<bean id="p1" class="org.alexhe.bean.Computer">
<!-- 信息set注入 -->
<property name="cpu" value="骁龙"></property>
<property name="hdd" value="希捷"></property>
<property name="mainboard" value="华硕"></property>
</bean>
<bean id="p2" class="org.alexhe.bean.Computer">
<!-- 构造器注入 -->
<constructor-arg index="0" value="高通"></constructor-arg>
<constructor-arg index="1" value="2G"></constructor-arg>
</bean>
<bean id="s1" class="org.alexhe.bean.Student">
<!-- 利用set注入Computer -->
<property name="c" ref="p1"></property>
</bean>
测试类:
Student s=ac.getBean("s1",Student.class);
s.show();
unit02_1
1.自动注入=自动装配,简化注入配置,byType,byName,constructor
autowire="byType",按类型匹配,同类型只能出现一次。Student需要Computer组件,所以computer的注入只能出现一次。
<bean id="s2" class="org.alexhe.bean.Student" autowire="byType"></bean>
byName,按名字匹配,名字要和set方法的缩写一样。
2.各种类型信息的注入配置格式
a。注入字符串,数值单个数值
<property name="" value="">
b。注入bean对象
c。注入集合list,set,map,properties
d。spring表达式注入,#{表达式} #{id名.属性}或者#{id名.key}。如果是对象属性,需要有getXXX方法。
日期例子:主意用的是java.sql.date,特殊情况,这种例子以后用的不多。
import java.sql.Date;
public class MessageBean {
private String name;
private int age;
private Date birth;
public void show(){
System.out.println("name:"+name);
System.out.println("age:"+age);
System.out.println("birth"+birth);
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setBirth(String birth) {
Date date=Date.valueOf(birth);
this.birth = date;
}
}
xml:注意传入的是字符串
<bean id="msg" class="org.alexhe.bean.MessageBean">
<property name="name" value="root"></property>
<property name="age" value="18"></property>
<property name="birth" value="2017-05-05"></property>
</bean>
测试类:
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
MessageBean msg=ac.getBean("msg",MessageBean.class);
msg.show();
List集合例子:
private List<String> friends;
xml:
<property name="friends">
<list>
<value>tom</value>
<value>jack</value>
</list>
</property>
Set集合例子:
private Set<String> cities;
xml:
<property name="cities">
<set>
<value>北京</value>
<value>上海</value>
</set>
</property>
Map集合例子:
private Map<String,String> books;
xml:
<property name="books">
<map>
<entry key="1001" value="java基础"></entry>
<entry key="1002" value="python基础"></entry>
</map>
</property>
Properties例子:
private Properties db;
xml:
<property name="db">
<props>
<prop key="username">alex</prop>
<prop key="password">1234</prop>
</props>
</property>
以上所有的完整xml:
<bean id="msg" class="org.alexhe.bean.MessageBean">
<property name="name" value="root"></property>
<property name="age" value="18"></property>
<property name="birth" value="2017-05-05"></property>
<property name="friends">
<list>
<value>tom</value>
<value>jack</value>
</list>
</property>
<property name="cities">
<set>
<value>北京</value>
<value>上海</value>
</set>
</property>
<property name="books">
<map>
<entry key="1001" value="java基础"></entry>
<entry key="1002" value="python基础"></entry>
</map>
</property>
<property name="db">
<props>
<prop key="username">alex</prop>
<prop key="password">1234</prop>
</props>
</property>
</bean>
unit02_2
xml里bean的外部定义List ,set,map的方法(这样可以重用)
xml里的约束:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
xml:
<!-- 定义List<String>对象 -->
<util:list id="someList">
<value>java</value>
<value>python</value>
</util:list>
<!-- 定义Set<String>对象 -->
<util:list id="someSet">
<value>beijing</value>
<value>上海</value>
</util:list>
<!-- 定义Map<String,String>对象 -->
<util:map id="someMap">
<entry key="1003" value="oracle"></entry>
<entry key="1004" value="mysql"></entry>
</util:map>
<!-- 定义Properties对象 -->
<util:properties id="someProp">
<prop key="username">root</prop>
<prop key="password">pass</prop>
</util:properties>
<bean id="msg1" class="org.alexhe.bean.MessageBean">
<property name="friends" ref="someList"></property>
<property name="cities" ref="someSet"></property>
<property name="books" ref="someMap"></property>
<property name="db" ref="someProp"></property>
</bean>
java的src下面有个db.properties
<bean id="msg1" class="org.alexhe.bean.MessageBean">
<property name="friends" ref="someList"></property>
<property name="cities" ref="someSet"></property>
<property name="books" ref="someMap"></property>
<property name="db" ref="dbParams"></property>
</bean>
<!-- 读取src下的db.properties,行程Properties对象 -->
<util:properties id="dbParams" location="classpath:db.properties">
</util:properties>
spring表达式注入:#{表达式} #{id名.属性}或者#{id名.key}。如果是对象属性,需要有getXXX方法。
<bean id="msg1" class="org.alexhe.bean.MessageBean">
<property name="friends" ref="someList"></property>
<property name="cities" ref="someSet"></property>
<property name="books" ref="someMap"></property>
<property name="db" ref="dbParams"></property>
<property name="name" value="#{dbParams.user}"></property> 如果要调用上一章springcontext里的msg的name,应该写成#{msg.name} #{someList[1]}这样取到的是python
</bean>
<!-- 读取src下的db.properties,行程Properties对象 -->
<util:properties id="dbParams" location="classpath:db.properties">
</util:properties>
3.利用注解配置应用IOC
在jdk5.0时追加一些新特性:
List<String> 泛型
for(String s:list)增强for循环
Integer i=10;自动装箱拆箱
注解:在类定义,方法定义,成员变量定义,前面使用,格式为@注解标记名。
public void f1(String .. s){} 动态参数
a。组件自动扫描
可以按指定的包路径,将包下所有组件扫描,如果发现组件类定以前有以下标记,会将组件扫描到Spring容器。
@Component
@Controller//控制层
@Service//业务层
@Repository//数据访问层Dao
@Named(需要引入第三方标准包)
@Scope控制对象创建
@PostConstruct指定init-method
@PreDestroy指定destroy-method
@Resource可以在变量定义前活着setXX方法前应用。按默认名称规则装配,@Resource(name="p1")按指定名字装配
@Autowired可以在变量定义前活着setXX方法前应用。按类型自动装配
@Qualifier("id名")按照名字自动装配,如果autowire有两个想同类型,可以和qualifier配合使用。
@Value("") spring表达式注入
resource和autowire在一般使用时,功能相同,都可以实现注入。如果不存在多个匹配类型,使用两者都行。
如果有多个匹配类型,建议按名称注入@Resource(name="指定名称")。
而autowire有多个匹配类型就要配合qualifier一起使用
例子:
@Component("ds")
public class MyDataSource{
@Value("#{db.username}")//取出xml名字为db的组件,key为username
private String username;
@Value("#{db.password}")
private String password;
public void getConnection(){
System.out.pringln("利用链接参数创建数据库连接");
}
//省略set方法
}
xml:
直接写<beans>里
<!-- srping创建一个properties对象,然后利用@Value表达式注入,将properties对象信息给MyDataSource注入-->
<util:properties id="db">
<prop key="username">alex</prop>
<prop key="password">1234</prop>
</util:properties>
请求-->DispatcherServlet-->Controller-->Service-->Dao
例子:
xml:
<!-- 开启组件扫描 扫描此包下和子包下所有组件-->
<context:component-scan base-package="org.alexhe"/>
java代码:
@Component//扫描ExampleBean组件,默认id=exampleBean,并且是单例的
public class ExampleBean {
public void execute(){
System.out.println("执行execute处理方法");
}
}
@Component("exam1")//指定id=exam1
@Scope("prototype")//等价于<bean scope="prototype"></bean>
public class ExampleBean1 {
@PostConstruct//等价于<bean init-method="">
public void init(){
System.out.println("init方法");
}
@PreDestroy//等价于<bean destroy-method=""> 很少用,最上面已经介绍。
public void destroy(){
System.out.println("释放资源");
}
public void execute(){
System.out.println("exampleBean1执行execute处理方法");
}
}
b。注入注解
方式一:使用resource注解放在变量定义前
computer类:
@Component("c")
public class Computer {
public void show(){
System.out.println("显示计算机配置信息");
}
}
Phone类:
@Component("p")
public class Phone {
public void show(){
System.out.println("显示手机配置信息");
}
}
Student类:
@Component("s")
public class Student {
//需要调用computer和phone对象
@Resource//默认按名称方式传递进来,如果找不到c对象才会按类型注入
private Computer c;
@Resource
private Phone p;
public void show(){
System.out.println("显示学生信息");
c.show();
p.show();
}
public void setC(Computer c) {
this.c = c;
}
public void setP(Phone p) {
this.p = p;
}
}
xml:
<!-- 开启组件扫描 扫描此包下和子包下所有组件-->
<context:component-scan base-package="org.alexhe"/>
测试类:
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Student s=ac.getBean("s",Student.class);
s.show();
方式二:在Student类的setComputer和setPhone方法前加注解@Resource,变量前不加。
方式三:使用@Autowired注解,和方式一和方式二一样,加在变量前或者setXXX方法前。autowired默认按类型来注入。
resource和autowire的区别:resource注解用的是javax.annotation.Resource autowired使用的是spring包里的。 resource可以有两个相同类型的组件比如两个Computer,而autowired不能有两个同类型的。
注解和xml管理的区别:注解可以没有set方法(比如Student可以没有setComputer和setPhone),但xml一定要有set方法。
autowire和qualifier配合使用的例子:
@Autowired//按类型
public void SetP(@Qualifier("anotherp") Phone p){
this.p=p;
}
或者:
@Autowired//按类型
@Qualifier("anotherp")
public void SetP(Phone p){
this.p=p;
}
的