1、对象的生命周期
2、Spring管理数据库连接池(重点)
3、Spring EL表达式(工作中不常用)
4、注解功能(极其重要)
5、Spring的专有测试
1、对象的生命周期
1.1、IOC之Bean的生命周期
实验1:创建带有生命周期方法的bean
给A类添加生命周期方法:
public class A {
public A() {
System.out.println("这是A对象被创建了");
}
public void initA() {
System.out.println("这里是初始化A的方法");
}
public void destroyA() {
System.out.println("这里是销毁A的方法");
}
}
在xml配置文件中配置如下:
<!--
init-method="initA" 设置初始化方法
destroy-method="destroyA" 设置销毁的方法
-->
<bean id="a" class="com.tcent.pojo.A" init-method="initA" destroy-method="destroyA"></bean>
测试的代码:
@Test
public void test23() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application2.xml");
applicationContext.close();
}
1.2、Bean的后置处理器BeanPostProcessor
功能:只在bean标签属性init-method属性对应的初始化方法之前与之后做一些处理
实验2:测试bean的后置处理器

创建一个AI接口
public interface AI {
public void show();
}
修改A类实现AI接口
public class A implements AI {
public A() {
System.out.println("这是A对象被创建了");
}
public void initA() {
System.out.println("这里是初始化A的方法");
}
public void destroyA() {
System.out.println("这里是销毁A的方法");
}
@Override
public void show() {
System.out.println("--这是目标A对象的show方法--");
}
}
Processor:处理器
1、创建一个类去实现后置处理器的接口
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("这是初始化之前: bean->[" + bean + "] , beanName ->["
+ beanName + "]");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("这是初始化之后: bean->[" + bean + "] , beanName ->["
+ beanName + "]");
if ("a".equals(beanName)) {
// 创建一个jdk动态代理
AI proxyAi = (AI) Proxy.newProxyInstance(bean.getClass()
.getClassLoader(), bean.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
System.out.println("这是前置增强代码");
Object result = method.invoke(bean, args);
System.out.println("这是后置增强代码");
return result;
}
});
return proxyAi;
} else {
return bean;
}
// return bean;
}
}
2、到Spring的配置文件中去配置后置处理器
<!--
init-method="initA" 设置初始化方法
destroy-method="destroyA" 设置销毁的方法
-->
<bean id="a" class="com.tcent.pojo.A" init-method="initA" destroy-method="destroyA"></bean>
<!-- 配置Bean的后配置处理器。 -->
<bean class="com.tcent.util.MyBeanPostProcessor" />
测试的代码:
@Test
public void test24() {
@SuppressWarnings("resource")
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"application2.xml");
AI ai = (AI) applicationContext.getBean("a");
ai.show();
}
测试结果:

2、Spring管理数据库连接池(重点)
再次搭建Spring的开发环境:
1、创建一个Java工程

2、导入Spring需要的jar包
commons-logging-1.1.3.jar(下面四个核心包的依赖包)
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
3、还有日记包
log4j-1.2.17.jar
4、log4j.properties属性配置文件
# Global logging configuration
log4j.rootLogger=INFO, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
5、还需要导入数据库驱动包以及数据库连接池
c3p0-0.9.1.2.jar
mysql-connector-java-5.1.37-bin.jar
6、创建Spring的配置文件application.xml

2.1、Spring配置管理数据库连接池对象(重点)
1、在Spring的配置文件中配置数据库连接池对象
<?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.xsd">
<!-- 配置一个数据库连接池对象 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/book" />
<property name="user" value="root" />
<property name="password" value="root" />
<property name="driverClass" value="com.mysql.jdbc.Driver" />
</bean>
</beans>
1、测试的代码:
public class ApplicationTest {
@Test
public void test1() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"application.xml");
DataSource dataSource = (DataSource) applicationContext.getBean("dataSource");
System.out.println(dataSource.getConnection());
}
}
2.2、Spring引入单独的jdbc.properties配置文件(重点)
1、抽取四个jdbc连接属性到jdbc.properties属性配置文件中
jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/book
jdbc.driverClass=com.mysql.jdbc.Driver
2、以前都是使用PropertyPlaceholderConfigurer 来加载jdbc.properties属性配置文件
<!-- 它可以加载jdbc.properties属性配置文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!-- location 属性是你要加载的jdbc.properties属性配置文件的路径 -->
<property name="location" value="classpath:jdbc.properties" />
</bean>
3、使用加载后的jdbc.properties属性配置文件中的连接属性。
<!-- 配置一个数据库连接池对象 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
<property name="driverClass" value="${jdbc.driverClass}" />
</bean>
2.3、使用context名称空间加载jdbc.properties配置文件(重点)

现在:
<!-- 也可以加载classpath路径下的jdbc.properties属性配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
3、Spring EL表达式
创建java实体Bean对象
public class Person {
private int id;
private String name;
private String phone;
private double salary;
private Car car;
public class Car {
private String name;
private String carNo;
<bean id="car" class="com.tcent.pojo.Car">
<property name="name" value="宝马" />
<property name="carNo" value="京B123421" />
</bean>
<bean id="personEL" class="com.tcent.pojo.Person">
<!-- 实验3:[SpEL测试I]在SpEL中使用字面量 -->
<!-- 使用格式:#{数值} #{“字符串” || ‘字符串’} -->
<!-- <property name="name" value="#{'这是EL表达式常量值'}" /> -->
<!-- 实验4:[SpEL测试II]在SpEL中引用其他bean -->
<!-- 使用格式:#{bean的id} -->
<property name="car" value="#{car}"/>
<!-- 实验5:[SpEL测试III]在SpEL中引用其他bean的某个属性值 -->
<!-- 使用格式: #{bean.属性名} -->
<property name="phone" value="#{car.name}" />
<!-- 实验6:[SpEL测试IV]在SpEL中调用非静态方法 -->
<!-- 使用格式: #{bean.方法名(参数)} -->
<!-- <property name="name" value="#{car.fun1()}"/> -->
<!-- 实验7:[SpEL测试V]在SpEL中调用静态方法 -->
<!-- 使用格式:#{T(全名类).方法名(参数)} -->
<property name="name" value="#{T(com.tcent.pojo.Car).staticFun()}" />
<!-- 实验8:[SpEL测试VI]在SpEL中使用运算符 -->
<!-- 使用格式:#{表达式} -->
<property name="salary" value="#{10*1024}"/>
</bean>
4、注解功能(极其重要)
4.1、注解配置类Dao、Service、Controller组件
当我们使用Spring的注解功能的时候。需要把aop的jar包导入
不导包就会发生如下错误:

实验9:通过注解分别创建Dao、Service、Controller★
Spring配置bean的常用注解有
@Controller 专门标注给web层的组件(对象)
@Service 专门给Service层的组件注解
@Repository 给Dao层组件标注
@Component 给Dao、Service、控制器Web层之外的组件进行标注。
@Scope可以修改bean的Scope属性,默认不标注此注解表示单例。
也可以通过注解修改为多例@Scope(value="prototype")
注:前面4种注解功能一样,注解本身不会做检查,只是约定好的这样使用,如果非要用在其他地方,也可以的。在注解的时候,如果是单个value=“”注解,可以省略value。
注解在类上的使用:
/**
* @Repository注解的功能相当于在Spring配置文件中做了如下的配置:
* <bean id="bookDao" class="com.tcent.dao.BookDao" scope="singleton"></bean>
*/
@Scope(value="prototype")
@Repository(value="bookDao")
public class BookDao {
public BookDao() {
System.out.println("BookDao也被初始化了");
}
}
当我们在类上使用了注解之后。一定要在Spring配置文件中加上包扫描的配置才能生效
<!-- context:component-scan 表示包扫描
base-package 指定要扫描哪些包下的类(并且包含子包)
-->
<context:component-scan base-package="com.tcent"></context:component-scan>
测试代码:
@Test
public void test1() throws Exception {
@SuppressWarnings("resource")
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
System.out.println( applicationContext.getBean("bookDao") );
}
4.2、指定扫描包时的过滤内容(重要)
实验10:使用context:include-filter指定扫描包时要包含的类
实验11:使用context:exclude-filter指定扫描包时不包含的类
<context:include-filter />设置包含的内容
注意:通常需要与use-default-filters属性配合使用才能够达到“仅包含某些组件”这样的效果。即:通过将use-default-filters属性设置为false,
<context:exclude-filter />设置排除的内容
默认都是包含的 即:use-default-filters=ture
类别 | 示例 | 说明 |
annotation | com.tcent.XxxAnnotation | 过滤所有标注了XxxAnnotation的类。这个规则根据目标组件是否标注了指定类型的注解进行过滤 |
assignable | com.tcent.BaseXxx | 过滤所有BaseXxx类的子类。这个规则根据目标组件是否是指定类型的子类的方式进行过滤。 |
aspectj | com.tcent.*Service+ | 所有类名是以Service结束的,或这样的类的子类。这个规则根据AspectJ表达式进行过滤。 |
regex | com\.tcent\.anno\.* | 所有com.tcent.anno包下的类。这个规则根据正则表达式匹配到的类名进行过滤。 |
custom | com.tcent.XxxTypeFilter | 使用XxxTypeFilter类通过编码的方式自定义过滤规则。该类必须实现org.springframework.core.type.filter.TypeFilter接口 |
applicationContext.xml 中配置的内容如下
<!-- use-default-filters="false" 设置取消默认包含规则 -->
<context:component-scan base-package="com.tcent" use-default-filters="false">
<!-- context:include-filter 设置包含的内容 -->
<!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> -->
<!-- context:exclude-filter 设置排除的内容 -->
<context:exclude-filter type="assignable" expression="com.tcent.service.BookService"/>
</context:component-scan>
以上配置会包含所有@Service注解的类。排除com.tcent.service.BookService类
注:context:exclude-filter不可与context:include-filter同时使用,并且一般使用context:exclude-filte过滤就可以了,context:include-filter的作用不大,几乎不怎么用
说明:如果要使用的include话,一定要和use-default-filters="false"同时使用,但使用了use-default-filters="false"就表示所有的都不包含,再加上exclude过滤排除不包含就没有意义了,除非是include修饰已有的,但两个作用一个上面没意义,会包错。
4.3、使用注解@Autowired自动装配(对比上一篇使用xml自动注入)
实验12:使用@Autowired注解实现根据类型实现自动装配★
@Autowired 注解 会自动的根据已标注的对象类型(因为是根据到spring容器中去查找,而容器中的必须是已标注过的)(xml中byType)在Spring容器中查找相对应的类。如果找到,就自动装配。
使用@Autowired注解,不需要get/set方法
@Repository
public class BookDao {
public BookDao() {
System.out.println("BookDao也被初始化了");
}
}
@Service("bookService")
public class BookService {
public BookService() {
System.out.println("bookService被初始化了");
}
/**
* 实验:使用@Autowired注解实现根据类型实现自动装配★<br/>
* 1、Spring容器会自动的根据对象的类型到Spring容器中去查找,然后注入值。
* 1、如果找到一个,就直接注入值<br/>
*/
@Autowired
private BookDao bookDao;
@Override
public String toString() {
return "BookService [bookDao=" + bookDao + "]";
}
}
4.4、多个同类型的bean如何自动装配
实验13:如果资源类型的bean不止一个(同xml中byName),(同constructor)默认根据@Autowired注解标记的成员变量名作为id查找bean,进行装配
@Repository
public class BookDao {
public BookDao() {
System.out.println("BookDao也被初始化了");
}
}
@Repository
public class BookDaoExt extends BookDao{
public BookDaoExt() {
System.out.println("BookDaoExt也被初始化了");
}
}
@Service("bookService")
public class BookService {
public BookService() {
System.out.println("bookService被初始化了");
}
/**
* 实验13:使用@Autowired注解实现根据类型实现自动装配★<br/>
* 1、Spring容器会自动的根据对象的类型到Spring容器中去查找,然后注入值。
* 1、如果找到一个,就直接注入值<br/>
* 2、如果找到多个,Spring容器会自动按照@Autowired标注的变量做为id来查找
* 2.1、查找就注入
* 2.2、找不到就报错。
*/
@Autowired
private BookDao bookDao;
@Override
public String toString() {
return "BookService [bookDao=" + bookDao + "]";
}
}
4.5、使用@Qualifier装配指定id的bean对象
实验14:如果根据成员变量名作为id还是找不到bean(起别名了),可以使用@Qualifier注解明确指定目标bean的id
@Repository(value="aaa")
public class BookDao {
public BookDao() {
System.out.println("BookDao也被初始化了");
}
}
@Repository(value="bbb")
public class BookDaoExt extends BookDao{
public BookDaoExt() {
System.out.println("BookDaoExt也被初始化了");
}
}
实验13:使用@Autowired注解实现根据类型实现自动装配★<br/>
1、Spring容器会自动的根据对象的类型到Spring容器中去查找,然后注入值。
1、如果找到一个,就直接注入值<br/>
2、如果找到多个,Spring容器会自动按照@Autowired标注的变量做为id来查找
2.1、查找就注入
2.2、找不到就报错。
@Qualifier 这个注解,可以给你标注的组件。按照给定的id去spring容器中查找,然后注入。
这个注解会改变默认规则,默认是按照变量名,做为id来查找。但是,当使用了。这个注解之后。就会按照给定的id来查找。
如果找到指定id的bean对象,就注入。如果找不到就报错
别名:@Qualifier("bbb")
private BookDao bookDao;
4.6、@Autowired注解的required属性作用
实验:@Autowired注解的required属性指定某个属性允许不被设置
实验13:使用@Autowired注解实现根据类型实现自动装配<br/>
1、Spring容器会自动的根据对象的类型到Spring容器中去查找,然后注入值。
1、如果找到一个,就直接注入值<br/>
2、如果找到多个,Spring容器会自动按照@Autowired标注的变量做为id来查找
2.1、查找就注入
2.2、找不到就报错。
3、@Autowired注解中有一个属性,叫required是必须,必要的意思,默认值是true,
表示被标注的bean对象,必须要有值注入。如果找不到注入,就报错。
但如果找不到,不希望它报错。就把此值改为false。则此对象的值可以为null。
@Autowired(required=false)
@Qualifier 这个注解,可以给你标注的组件。按照给定的id去spring容器中查找,然后注入。
这个注解会改变默认规则,默认是按照变量名,做为id来查找。但是,当使用了。这个注解之后。就会按照给定的id来查找。
如果找到指定id的bean对象,就注入。如果找不到就报错
@Qualifier("ccc")
private BookDao bookDao;
4.7、@Autowired和@Qualifier在方法上的使用。
实验15:在方法的形参位置使用@Qualifier注解
注:@Qualifier要和@Autowired一起使用才起作用
private BookDao bookDaoExt;
/**
* @Autowired 注解标注的方法和组件都是初始化的时候,就已经调用和注入了。<br/>
*/
@Autowired
public void abc(@Qualifier(value = "aaa") BookDao bookDao) {
System.out.println("这是被标注了@Autowired注解的方法…………");
System.out.println(bookDao);
this.bookDaoExt = bookDao;
}
4.8、泛型注入
实验16:测试泛型依赖注入

接口的继承树

所有的Dao代码:
public abstract class BaseDao<T> {
public abstract void save(T entity);
}
@Repository
public class BookDao extends BaseDao<Book> {
@Override
public void save(Book entity) {
System.out.println("这是BookDao,保存一个Book --->>>" + entity);
}
}
@Repository
public class UserDao extends BaseDao<User> {
@Override
public void save(User entity) {
System.out.println("这是UserDao,保存一个User --->>>" + entity);
}
}
所有的Service代码:
public abstract class BaseService<T> {
@Autowired
protected BaseDao<T> dao;
public void save(T entity) {
dao.save(entity);
}
}
@Service
public class BookService extends BaseService<Book> {
}
@Service
public class UserService extends BaseService<User> {
}
Spring的配置文件内容:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 扫描全部的包 -->
<context:component-scan base-package="com.tcent"></context:component-scan>
</beans>
测试的代码:
public class SpringTest {
@Test
public void test1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
BookService bookService = (BookService) applicationContext.getBean("bookService");
bookService.save(new Book());
UserService userService = (UserService) applicationContext.getBean("userService");
userService.save(new User());
}
}
5、Spring的专有测试
先导入spring-test-4.0.0.RELEASE.jar包
其强大之处可以在测试类里面加注解,前提还是要导入JUnit4包才可以
@ContextConfiguration(locations = "classpath:application.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringJunit {
@Autowired
private BookService bookService;
@Autowired
private UserService userService;
@Autowired
private UserDao userDao;
@Test
public void test1() {
bookService.save(new Book());
userService.save(new User());
System.out.println(userDao);
}
}
spring-test-4.0.0.RELEASE.jar
spring-aop-4.0.0.RELEASE.jar
下载