Spring详解二之注解功能及其他


1、对象的生命周期

2Spring管理数据库连接池(重点)

3Spring EL表达式(工作中不常用)

4、注解功能(极其重要)

5Spring的专有测试

1、对象的生命周期

1.1IOCBean的生命周期

实验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.2Bean的后置处理器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();
	}

测试结果:


2Spring管理数据库连接池(重点)

再次搭建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

 

4log4j.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.1Spring配置管理数据库连接池对象(重点)

 

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.2Spring引入单独的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"/>

3Spring 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、注解配置类DaoServiceController组件

当我们使用Spring的注解功能的时候。需要把aopjar包导入

不导包就会发生如下错误:


实验9:通过注解分别创建DaoServiceController

Spring配置bean的常用注解有

@Controller   专门标注给web层的组件(对象)

@Service 专门给Service层的组件注解

@Repository Dao层组件标注

@Component DaoService、控制器Web层之外的组件进行标注。

@Scope可以修改beanScope属性,默认不标注此注解表示单例。

也可以通过注解修改为多例@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容器中去查找,而容器中的必须是已标注过的)(xmlbyTypeSpring容器中查找相对应的类。如果找到,就自动装配。

使用@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不止一个(同xmlbyName),(同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装配指定idbean对象

实验14:如果根据成员变量名作为id还是找不到bean(起别名了),可以使用@Qualifier注解明确指定目标beanid

@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());
	}
	
}

5Spring的专有测试

先导入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

下载

Spring详解一之IOC






猜你喜欢

转载自blog.csdn.net/mxcsdn/article/details/80697812
今日推荐