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
下载