您的位置:首页 > 编程语言 > Java开发

JavaEE学习笔记之SSH—Spring(2)

2016-07-15 00:20 351 查看
1 xml文件导入其他xml文件配置

如果我们在spring框架中配置了多个xml文件,我们可以在读取配置文件的时候把这些xml文件一下全都读取,也可以只读一个总的xml文件,在这个总的xml文件中把其他的xml全都都导入进来。

例如:

student.xml文件:

<bean name="student" class="com.briup.bean.Student">
<property name="id">
<value>25</value>
</property>
</bean>


teacher.xml文件:


<bean name="teacher" class="com.briup.bean.Teacher">
<property name="student" ref="student"></property>//ref=""手动注入哪个bean
</bean>


import.xml文件:


<import resource="teacher.xml"/>
<import resource="student.xml"/>


main:


String[] path = {"com/briup/ioc/imp/import.xml"};
//或 String[] path = {"com/briup/ioc/imp/student.xml","com/briup/ioc/imp/teacher.xml"}
ApplicationContext container = new ClassPathXmlApplicationContext(path);

Teacher t = (Teacher) container.getBean("teacher");
System.out.println(t.getStudent());


2 创建bean实例的方式

1) xml文件中有bean的配置,而且这个bean所对应的java类中存在一个无参构造器,那么这个时候spring容器就可以使用反射调用无参构造器来创建实例了

2) 通过工厂类获得实例(工厂类实现了接口FactoryBean

工厂类实现指定接口并且实现接口中的三个抽象方法:
public class ConnectionFactory implements FactoryBean<Connection>{
private String driver;
private String url;
private String username;
private String password;

@Override
public Connection getObject() throws Exception {
Class.forName(driver);
Connection conn =
DriverManager.getConnection(url,username,password);
return conn;
}

@Override
public boolean isSingleton() {//判断它是否是单例
// TODO Auto-generated method stub
return false;
}

@Override
public Class<Connection> getObjectType() {
// TODO Auto-generated method stub
return Connection.class;
}
set/get
....
}


xml文件:
<!--
因为这个类是一个工厂类,所以我们用名字conn在容器中拿对象的时候,
拿到并不是这个工厂类对象,而是这个工厂类对象调用完工厂方法后所返回的对象.
-->


<bean name="conn" class="com.briup.ioc.factory.ConnectionFactory">
<property name="driver">
<value>${driver}</value>//从一个配置文件中以key—value的形式拿value
</property>

<property name="url">
<value>${url}</value>
</property>

<property name="username">
<value>${username}</value>
</property>

<property name="password">
<value>${password}</value>
</property>
</bean>

<!--
下面配置的这个类,可以自动的帮我们去读取指定的properties文件的
内容,文件中用key-value的形式存放数据,读完之后我们就可以用
${key}这种形式去拿文件中的value值了。
classpath指的是从src下面找.
-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:oracle.properties</value>
</property>
</bean>


  main:


String path = "com/briup/ioc/factory/factory.xml";
ApplicationContext container =
new ClassPathXmlApplicationContext(path);
Connection conn = (Connection) container.getBean("conn");
System.out.println(conn);


3) 通过实例工厂获得实例(不需要实现或者继承任何接口或者父类)

注意spring中的PropertyPlaceholderConfigurer类的使用,在htmlsingle中直接搜索类名即可

例如:一个普通的工程类

public class ConnectionFactory{
private String driver;
private String url;
private String username;
private String password;

public Object getConnection() throws Exception {
Class.forName(driver);
Connection conn = DriverManager.getConnection(url,username,password);
return conn;
}
get/set
....
}


xml文件:


<bean name="factory" class="com.briup.ioc.instanceFactory.ConnectionFactory">
<property name="driver">
<value>${driver}</value>
</property>

<property name="url">
<value>${url}</value>
</property>

<property name="username">
<value>${username}</value>
</property>

<property name="password">
<value>${password}</value>
</property>
</bean>

<!--
将来通过这个conn来拿对象,拿到的是名字为factory的工厂类调用完
名字为getConnection方法之后所返回的对象。
-->
<bean name="conn" factory-bean="factory" factory-method="getConnection"></bean>

<!-- 读取properties文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:oracle.properties</value>
</property>
</bean>


   main:


String path = "com/briup/ioc/instanceFactory/instanceFactory.xml";
ApplicationContext container =
new ClassPathXmlApplicationContext(path);
Connection conn = (Connection) container.getBean("conn");
System.out.println(conn);


4) 通过静态工厂获得实例

例如:含义静态方法的工厂类

public class ConnectionFactory{
private static String driver = "oracle.jdbc.driver.OracleDriver";
private static String url = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
private static String username = "briup";
private static String password = "briup";

public static Connection getConnection() throws Exception {
Class.forName(driver);
Connection conn = DriverManager.getConnection(url,username,password);
return conn;
}
}


xml文件:


<!-- 这样配置一定要求getConnection方法是静态方法 -->
<bean name="conn" class="com.briup.ioc.staticFactory.ConnectionFactory" factory-method="getConnection"></bean>


  main:


String path = "com/briup/ioc/staticFactory/staticFactory.xml";
ApplicationContext container = new ClassPathXmlApplicationContext(path);
Connection conn = (Connection) container.getBean("conn");
System.out.println(conn);


3 自定义属性编辑器 PropertyEditor

Spring中我们可以使用属性编辑器来将特定的字符串转换为对象 :String–>object

java.beans.PropertyEditor(JDK中的接口)用于将xml文件中字符串转换为特定的类型

同时JDK为我们提供一个实现类 java.beans.PropertyEditorSupport

Spring在注入时,如果遇到类型不一致(例如需要Address类型但是用户传了个String)则会去调用相应的属性编辑器进行转换.

spring会调用属性编辑器的setAsText(String str)进行处理用户传的字符串,并调用getValue()方法获取处理后得到的对象,所以我们在代码中处理完后记得调用setValue方法,要不然spring调用getValue方法拿不到你处理后的对象

自定义属性编辑器示例:

**注意**spring中的CustomEditorConfigurer类的使用,在htmlsingle中直接搜索类名即可

//自定义编辑器类
public class AddressEditor extends PropertyEditorSupport {
@Override
public String getAsText() {
return super.getAsText();
}
//Spring遇到数据类型不一致并且不能自己处理的时候会调用这个方法处理字符串
@Override
public void setAsText(String text) throws IllegalArgumentException {
String[] str = text.split(",");
String city = str[0];
String street = str[1];
String country = str[2];
Address add = new Address(city, street, country);
setValue(add);
}

}
//Address类
public class Address {
private String city;
private String street;
private String country;
set/get
.....
}

//Student类
public class Student {
private long id;
private String name;
private boolean gender;
private int age;
private Address address;
get/set
...
}


xml文件:<!-- 这个配置指明哪个类型对应哪个自定义编辑器 -->


<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="com.briup.ioc.proEdit.Address"  value="com.briup.ioc.proEdit.AddressEditor"/>
</map>
</property>
</bean>
<!-- spring发现address的值不能注入的时候(类型不对),就会调用对应的属性编辑器处理了 -->
<bean id="student" class="com.briup.ioc.proEdit.Student">
<property name="id" value="1"/>
<property name="name" value="tom"/>
<property name="age" value="45"/>
<property name="gender" value="true"/>
<property name="address">
<value>kunshan,xueyuan,China</value>
</property>
</bean>


4 自定义事件

在spring中我们可以自定义事件,并且可以使用ApplicationContext类型对象(就是spring容器container)来发布这个事件,事件发布之后,所有的ApplicaitonListener(监听器)实例都会被触发并调用指定方法onApplicationEvent()来处理.

例如:

自定义事件类RainEvent:
public class RainEvent extends ApplicationEvent {
public RainEvent(Object source) {
super(source);
}
}


监听器类RainListener1

public class RainListener1 implements ApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof RainEvent) {
System.out.println("唐僧大喊:" + event.getSource() + "赶快收衣服喽!");
}
}
}


监听器类RainListener2

public class RainListener2 implements ApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof RainEvent) {
System.out.println("我们:" + event.getSource() + "太好了不用上课了!");
}
}
}


xml文件:

<!-- 只需要把这俩个监听器类交给spring容器管理就可以了 -->
<bean class="com.briup.ioc.event.RainListener1"></bean>
<bean class="com.briup.ioc.event.RainListener2"></bean>


main:
String path = "com/briup/ioc/event/event.xml";
ApplicationContext container = new ClassPathXmlApplicationContext(path);
container.publishEvent(new RainEvent("下雨了!"));


5 ioc中的annotation配置

@Autowired

1) @Autowired默认按照byType匹配的方式进行注入,如果没有一个bean的类型是匹配的则会抛异常,

如果有多个bean的类型都匹配成功了,那么再按byName方式进行选择

2 )@Autowired注解可以写在成员变量、set/ger方法、构造器函数上面

3 )@Autowired如果最终匹配不成功(注意一定是一个都没有找到的情况)则会抛出异常,

但是如果设置为@Autowired(required=false),则最终匹配不成功没有不会抛出异常。

4 )@Autowired可以结合 @Qualifier(“beanName”)来使用,则可以达到byName的效果

5) @Autowired使用后需要在xml文件加入以下配置才能生效:

<!--新版本可以不需要加这里版本为4.7也不需要-->
<context:annotation-config/>


@Resource

1 )@Resource的作用和 @Autowired差不多,只不过@Resource是默认先用byName,

如果找不到合适的就再用byType来注入

2 )@Resource有俩个属性,name和type,使用name属性则表示要byName匹配,使用type属性则表示要byType匹配

3 )@Resource使用后需要在xml文件加入以下配置才能生效:

<!--新版本可以不需要加这里版本为4.7也不需要-->
<context:annotation-config/>


@PostConstruct 和 @PreDestroy

1 )标注了 @PostConstruct 注释的方法将在类实例化后调用。

2 )标注了 @PreDestroy 的方法将在类销毁之前调用。

@Component

1 )@Component注解可以直接定义bean,而无需在xml定义。但是若两种定义同时存在,注解会覆盖xml中的Bean定义。

2 )@Component注解直接写在类上面即可

3 )@Component有一个可选的参数,用于指定 bean 的名称:@Component(“boss”)

4 )@Component如果不指定参数,则 bean 的名称为当前类的类名小写

5 )@Component使用之后需要在xml文件配置一个标签:
<context:component-scan/>


6 ) 可以表示spring需要检查哪个包下的java类,看它们是否使用了 @Component注解

7 )@Component定义的bean默认情况下都是单例模式的,如果要让这个bean变为非单例,可以再结合这个 @Scope 注解来达到目标 @Scope(“prototype”)

@Component是Spring中所有bean组件的通用形式, @Repository @Service @Controller 则是 @Component的细化,用来表示更具体的用例,分别对应了持久化层、服务层和表现层。但是至少到现在为止这个四种注解的实质区别很小(甚至几乎没有),都是把当前类注册为spring容器中的一个bean

注意:

component-scan标签默认情况下自动扫描指定路径下的包(含所有子包),将带有 @Component @Repository @Service @Controller标签的类自动注册到spring容器。对标记了 Spring中的 @Required @Autowired @PostConstruct @PreDestroy @Resource @WebServiceRef @EJB @PersistenceContext @PersistenceUnit等注解的类进行对应的操作使注解生效(包含了annotation-config标签的作用)。

6,bean对象的生命周期

生命周期执行的过程如下:

1)spring对bean进行实例化,默认bean是单例

2)spring对bean进行依赖注入

3)如果bean实现了BeanNameAware接口,spring将bean的id传给setBeanName()方法

4)如果bean实现了BeanFactoryAware接口,spring将调用setBeanFactory方法,将BeanFactory实例传进来

5)如果bean实现了ApplicationContextAware()接口,spring将调用setApplicationContext()方法将应用上下文的引用传入

6) 如果bean实现了BeanPostProcessor接口,spring将调用它们的postProcessBeforeInitialization接口方法

7) 如果bean实现了InitializingBean接口,spring将调用它们的afterPropertiesSet接口方法,类似的如果bean使用了init-method属性声明了初始化方法,该方法也会被调用

8)如果bean实现了BeanPostProcessor接口,spring将调用它们的postProcessAfterInitialization接口方法

9)此时bean已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁

10)若bean实现了DisposableBean接口,spring将调用它的distroy()接口方法。同样的,如果bean使用了destroy-method属性声明了销毁方法,则该方法被调用

其实很多时候我们并不会真的去实现上面说描述的那些接口,那么下面我们就除去那些接口针对bean的单例和非单例来描述下bean的生命周期:

单例管理的对象:
1.默认情况下,spring在读取xml文件的时候,就会创建对象。

2.在创建的对象的时候(先调用构造器),再去调用init-method=".."
属性值中所指定的方法.

3.对象在被销毁的时候,会调用destroy-method="..."属性值中
所指定的方法.(例如调用container.destroy()方法的时候)

4.lazy-init="true",可以让这个对象在第一次被访问的时候创建(即延迟加载)

非单例管理的对象:
1.spring读取xml文件的时候,不会创建对象.

2.在每一次访问这个对象的时候,spring容器都会创建这个对象,并且
调用init-method=".."属性值中所指定的方法.

3.对象销毁的时候,spring容器不会帮我们调用任何方法,
因为是非单例,这个类型的对象有很多个,spring容器一旦把
这个对象交给你之后,就不再管理这个对象了.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: