第一个Spring程序
1、创建项目
2、导入jar包spring.jar
和commons-logging.jar
3、创建一个javabean类
public class Hello {
public void hello(){
System.out.println("hello");
}
}
4、在src目录下创建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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!--
beans
一个bean代表一个类
所以beans就是很多个类
-->
<!--
一个类
id 标示符
class 类的全名
-->
<bean id="hello" class="spring.com.bxp.bean.Hello">
</bean>
</beans>
5、创建测试类
public class Test {
public static void main(String[] args) {
//启动spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//从spring容器中提取bean
Hello hello = (Hello) context.getBean("hello");
hello.hello();
}
}
IOC
概念:把对象的创建,初始化,销毁交给Spring容器来做。
Spring创建对象的方式
1、构造函数
spring内部默认调用spring的构造函数创建对象
2、静态工厂
(1)创建静态工厂
public class HelloFactory {
public static Hello getInstance(){
return new Hello();
}
}
(2)配置工厂
<?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-2.5.xsd">
<!--
beans
一个bean代表一个类
所以beans就是很多个类
-->
<!--
一个类
id 标示符
class 类的全名
-->
<bean id="hello" class="spring.com.bxp.bean.Hello">
</bean>
<!-- 配置静态工厂 -->
<bean id="hello2" class="spring.com.bxp.bean.HelloFactory" factory-method="getInstance"></bean>
</beans>
(3)测试
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) context.getBean("hello2");
hello.hello();
}
}
3、实例工厂
(1)创建实例工厂(使用最多)
public class HelloFactory {
public Hello getInstance(){
return new Hello();
}
}
(2)配置实例工厂
<?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-2.5.xsd">
<!--
beans
一个bean代表一个类
所以beans就是很多个类
-->
<!--
一个类
id 标示符
class 类的全名
-->
<bean id="hello" class="spring.com.bxp.bean.Hello">
</bean>
<!-- 配置实例工厂 -->
<bean id="helloFactory" class="spring.com.bxp.bean.HelloFactory"></bean>
<!-- factory-bean对象工厂 factory-method对象工厂方法 -->
<bean id="hello3" factory-bean="helloFactory" factory-method="getInstance"></bean>
</beans>
(3)测试
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) context.getBean("hello3");
hello.hello();
}
}
使用别名
在applicationContext.xml文件中使用alias标签
<bean id="hello" class="spring.com.bxp.bean.Hello">
</bean>
<alias name="hello" alias="he"/>
对象的创建时机
默认创建方式
<bean id="hello" class="spring.com.bxp.bean.Hello">
1、加加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
2、根据配置文件中的配置的bean创建对象,配置多少个bean,创建多少个对象。
public Hello() {
// TODO Auto-generated constructor stub
System.out.println("构造方法 ");
}
3、获取对象
Hello hello = (Hello) context.getBean("hello3");
延迟创建(配置lazy-init属性)
<bean id="hello" lazy-init="true" class="spring.com.bxp.bean.Hello">
1、加加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
2、获取对象
Hello hello = (Hello) context.getBean("hello3");
//获取对象的同时创建对象
public Hello() {
// TODO Auto-generated constructor stub
System.out.println("构造方法 ");
}
意义
如果把lazy-init值改为true,在spring启动的时候,检测不到任何问题,会存在任何问题。所以一般情况下lazy-init的值为false。
如果一个bean中包含大量的数据,不希望bean过早的停留在内存中,此时将lazy-init的值改为true
对象的scope
在默认情况下(scope为singleton)
在spring中创建的对象的单例的。将来service和dao层所有的类将放到spring中,这两层中类的实例都是单例的,不能将属性声明在属性中,会出现线程安全问题。
scope为prototype:
<bean scope="prototype" id="hello" lazy-init="false" class="spring.com.bxp.bean.Hello">
lazy-init和prototype的结合
scope为prorotype,lazy-init为true
时:在context.getBean()时候创建对象
scope为prorotype,lazy-init为false时:在context.getBean()时候创建对象,lazy-init为false失效。
scope为prorotype,始终在context.getBean()时候创建对象
对象的创建和销毁
1、创建对象
public class Hello {
public void init(){
System.out.println("初始化方法");
}
public void destorym(){
System.out.println("销毁方法");
}
public void hello(){
System.out.println("hello");
}
public Hello() {
// TODO Auto-generated constructor stub
System.out.println("构造方法 ");
}
}
2、在配置文件中进行配置
<bean id="hello" class="spring.com.bxp.bean.Hello"
lazy-init="false" init-method="init"
destroy-method="destorym">
执行顺序
1、调用构造函数创建对象
2、有spring内部调用init()
方法进行对象的初始化
3、执行对象的方法
4、由执行context.coose()
方法时候,由spring内部调用destory()
方法
说明
1、init()
方法由spring内部调用
2、只有在spring容器关闭的时候才会执行,一般情况下spring容器是不会关闭的,只有在web容器销毁的时候才关闭。
3、如果bean的配置为scope="prototype"
,则spring容器不负责销毁。
IOC执行流程
DI(依赖注入)
给属性赋值
1、创建的对象Persion
public class Persion {
private long id;
private String name;
private List list;
private Set set;
private Map map;
private Properties pro;
private Hello hello;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public Set getSet() {
return set;
}
public void setSet(Set set) {
this.set = set;
}
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
public Properties getPro() {
return pro;
}
public void setPro(Properties pro) {
this.pro = pro;
}
public Hello getHello() {
return hello;
}
public void setHello(Hello hello) {
this.hello = hello;
}
}
2、在配置文件对属性进行配置
<bean id="persion" class="spring.com.bxp.bean.Persion">
<!-- name:属性, value:值, 引用类型使用ref赋值 -->
<property name="id" value="3"></property>
<property name="name" value="张三"></property>
<property name="hello" ref="hello"></property>
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
<ref bean="hello"/>
</list>
</property>
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
<ref bean="hello"/>
</set>
</property>
<property name="pro">
<props>
<prop key="pro1">pro1</prop>
<prop key="pro2">pro2</prop>
</props>
</property>
<property name="map">
<map>
<entry key="entry1">
<value>entry1</value>
</entry>
<entry key="entry2">
<ref bean="hello"/>
</entry>
</map>
</property>
</bean>
<bean id="hello" class="spring.com.bxp.bean.Hello"
lazy-init="false" init-method="init"
destroy-method="destorym">
</bean>
步骤:
1、spring容器实例化persion和hello两个bean对象
2、利用java的反射机制调用setter方法对属性进行赋值。
3、调用context.getBean()
获取对象。
如果配置了init()
方法,则先执行setter方法,在执行init方法
persion对象依赖于hello对象,如果在hello的bean标签上面加上lazy-init = true
的属性将会失效,因为创建persion对象必须创建hello对象。
使用构造器进行赋值
public Persion(long id, String name) {
super();
this.id = id;
this.name = name;
}
在配置文件中
<bean id="persion" class="spring.com.bxp.bean.Persion">
<constructor-arg index="0" value="1"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="张三"></constructor-arg>
</bean>
IOC和DI的意义:
实现了完全面向接口编程,客户端没有必要考虑具体的实现类是什么。
注解
概念
1、用来解释说明
2、必须作用于类的某一部分
3、注解的作用于范围(java,class,jvm)
4、注解解析器
自定义注解
类注解
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)//classInfo注解可以标注在类上
/**
* RetentionPolicy.SOURCE 只能在源代码上使用
*RetentionPolicy.CLASS 可以在源代码上和字节码上进行使用
*RetentionPolicy.RUNTIME 可以使用在源代码,字节码,jvm中
*/
@Retention(RetentionPolicy.RUNTIME)
@Documented //该注解能够出现在帮助文档中
public @interface ClassInfo {
String name() default "";//给该注解声明一个属性name,默认值为""
}
方法注解
@Target(ElementType.METHOD)//classInfo注解可以标注在类上
/**
* RetentionPolicy.SOURCE 只能在源代码上使用
*RetentionPolicy.CLASS 可以在源代码上和字节码上进行使用
*RetentionPolicy.RUNTIME 可以使用在源代码,字节码,jvm中
*/
@Retention(RetentionPolicy.RUNTIME)
@Documented //该注解能够出现在帮助文档中
public @interface MethodInfo {
String value() default "";
}
测试类
@ClassInfo(name = "这是类")
public class MyClass {
@MethodInfo("这是方法")
public void fun(){
}
}
解析注解
public void parse() {
Class clazz = MyClass.class;
if (clazz.isAnnotationPresent(ClassInfo.class)) {
ClassInfo classInfo = (ClassInfo) clazz
.getAnnotation(ClassInfo.class);
System.out.println(classInfo.name());
}
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(MethodInfo.class)) {
MethodInfo methodInfo = method.getAnnotation(MethodInfo.class);
System.out.println(methodInfo.value());
}
}
}
Spring中的注解
案例:
1、创建两个实体类Persion和Student
public class Persion {
@Resource(name = "student")
private Student student;
public void say(){
student.say();
}
}
public class Student {
public void say(){
System.out.println("student");
}
}
2、在配置文件中进行配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<bean id="persion" class="spring.com.bxp.bean.Persion"></bean>
<bean id="student" class="spring.com.bxp.bean.Student"></bean>
<!--
启动依赖注入的注解解析器
-->
<context:annotation-config></context:annotation-config>
</beans>
引入依赖注入的注解解析器需要的名称空间
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd"
3、测试
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Persion persion = (Persion) context.getBean("persion");
persion.say();
}
注解依赖注入的步骤:
1、启动spring容器
2、spring容器内部创建两个对象(Persion和Student)
3、当spring容器解析到<context:annotation-config></context:annotation-config>
时启动依赖注入解析器
4、spring容器在容器中查找所有的bean(Persion,Student)
5、查看meigebean的每个属性上是否有Resource注解
6、如果属性上面有该注解,则检查是否有name属性
7、如果没有name属性,则获取标注的属性的名称,然后将该名称和sping容器中的id进行匹配,如果匹配成功,则进行赋值。如果匹配不成功,则按照类型进行匹配,如果匹配成功则赋值,如果不成功,则报错。
8、如果有name属性,则把name属性的值解析出来,和spring容器中的id进行匹配,如果匹配成功,则赋值,如果不成功则报错。
综上所述:xml的效率高于注解,但是注解书写方便。
spring中定义的注解
1、按照类型进行匹配
@Autowired //按照类型进行匹配
2、按照id进行匹配
@Autowired
@Qualifier("student")