xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
默认是no,不启用自动装配!default-autowire 的类型有byName,byType,constructor;
byName:通过名称进行自动匹配;
byType:根据类型进行自动匹配;
constructor:和byType 类似,只不过它是根据构造方法注入而言的,根据类型,自动注入;
建议:自动装配机制慎用,它屏蔽了装配细节,容易产生潜在的错误;
class="com.test.spring.AutowireTest1" autowire="byName">
继承
这里说的继承和java的继承是不一样的,不是父类子类。但思想很相似,是父bean和子bean
1、父bean是一个实例时。它本身是一个完整的bean
2、父bean是模板,抽象bean,不能被实例化,只是来被继承。
当遇到一个类要实例化出很多相似的bean对象时,如下,看起来是不是很不简洁
1 <bean id="address1" class="com.guigu.spring.autowire.Address" 2 p:city="BeiJing" p:street="yihuan">bean> 3 <bean id="address2" class="com.guigu.spring.autowire.Address" 4 p:city="BeiJing" p:street="erhuan">bean>
方法① 两个bean除了p:street不一样,其他都一样。可以把一个作为父bean,其它的继承这个bean
1 <bean id="address1" class="com.guigu.spring.autowire.Address" 2 p:city="BeiJing" p:street="yihuan">bean> 3 <bean id="address2" p:street="erhuan" parent="address1">bean> 4 // address2等价于: 5 // <bean id="address2"" class="com.guigu.spring.autowire.Address" 6 // p:city="BeiJing" p:street="erhuan">bean>
这里,第二个就继承了第一个bean,用parent属性,只写自己独有的属性或要覆盖的属性即可。
方法②把相同属性提取出来,做一个抽象bean,专门用来继承
1 <bean id="address1" class="com.guigu.spring.autowire.Address" 2 p:city="BeiJing" p:street="yihuan" abstract="true">bean> 3 <bean id="address2" p:street="erhuan" parent="address1">bean>
这样,address2也继承了address1。address1设置了abstract="true",就不能实例化,否则抛异常。
也可以写成这样:
1 <bean id="address1" p:city="BeiJing" p:street="yihuan" abstract="true">bean> 2 <bean id="address2" class="com.guigu.spring.autowire.Address" p:street="erhuan" parent="address1">bean>
和上面的不同就是把class属性拿出去了。当很多不是同一个类的bean要继承父bean时,就要这样,在子bean写自己所在的class。
这样写还有一点是,这个父bean一定不能实例化,因为它没有class属性,实例化会跑异常。那就一定要写abstract属性,让spring不实例化它。
依赖---depends-on
用Person类的例子
1 public class Person { 2 private String name; 3 private Car car; 4 5 public String getName() { 6 return name; 7 } 8 public void setName(String name) { 9 this.name = name; 10 } 11 public Car getCar() { 12 return car; 13 } 14 public void setCar(Car car) { 15 this.car = car; 16 } 17 @Override 18 public String toString() { 19 return "Person [name=" + name + ", car=" + car + "]"; 20 } 21 }
有一个属性Car没有配置,那实例化后,它就是null。
1 <bean id="person" class="com.guigu.spring.autowire.Person" 2 p:name="Evan">bean>
有时,我们需要让某个属性必须存在,就像必填项一样。 用depends-on 依赖
1 <bean id="person" class="com.guigu.spring.autowire.Person" 2 p:name="Evan" depends-on="car">bean>
这样表示,实例化person一定要依赖car,没有配置car会抛异常
1 <bean id="car" class="com.guigu.spring.autowire.Car" p:brand="Audi" p:price="200000">bean> 2 <bean id="person" class="com.guigu.spring.autowire.Person" 3 p:name="Evan" depends-on="car">bean>
这样,依赖的car存在,就可以正常实例化了
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.user}"/>
<property name="password" value="${mysql.password}"/>
bean>
properties
内容:
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/xxx
mysql.user=xxx
mysql.password=xxx
Spring表达式语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言。
语法类似于EL:SpEL使用 #{…} 作为限定符,所有在大框号中的字符都将被认为是SpEL
SpEL为bean的属性进行动态赋值提供了便利
通过SpEL可以实现:
字面值的表示:
此处使用SpEL的意义不大
<property name="car" value="#{car}">property>
<property name="city" value="#{address.city}">property>
<property name="suffix" value="#{sequenceGenerator2.toString()}">
<property name="suffix" value="#{sequenceGenerator2.toString().toUpperCase()}">
<property name="tyrePerimeter" value="#{T(java.lang.Math).PI*80}">property>
if-else 运算符:?: (ternary), ?: (Elvis)
正则表达式:matches
Spring IOC 容器对 Bean 的生命周期进行管理的过程:
- 通过构造器或工厂方法创建 Bean 实例
在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法.
Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理.
Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例. 其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性.
对Bean 后置处理器而言, 需要实现 BeanPostProcessor 接口. 在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给上述接口的以下两个方法:
配置后置处理器:
实现 BeanPostProcessor 接口:
添加 Bean 后置处理器后 Bean 的生命周期
Spring IOC 容器对 Bean 的生命周期进行管理的过程:
- 通过构造器或工厂方法创建 Bean 实例
- 为 Bean 的属性设置值和对其他 Bean 的引用
- 将 Bean 实例传递给 Bean 后置处理器的 postProcessBeforeInitialization 方法
- 调用 Bean 的初始化方法
- 将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法
- Bean 可以使用了
- 当容器关闭时, 调用 Bean 的销毁方法
调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不同关心创建对象的细节.
要声明通过静态方法创建的 Bean, 需要在 Bean 的 class 属性里指定拥有该工厂的方法的类, 同时在 factory-method 属性里指定工厂方法的名称. 最后, 使用
实例工厂方法: 将对象的创建过程封装到另外一个对象实例的方法里. 当客户端需要请求对象时, 只需要简单的调用该实例方法而不需要关心对象的创建细节.
要声明通过实例工厂方法创建的 Bean
在 bean 的 factory-bean 属性里指定拥有该工厂方法的 Bean
在 factory-method 属性里指定该工厂方法的名称
使用 construtor-arg 元素为工厂方法传递方法参数
什么时候使用用FactoryBean?
组件扫描(component scanning): Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件.
特定组件包括:
@Component: 基本注解, 标识了一个受 Spring 管理的组件
@Respository: 标识持久层组件
@Service: 标识服务层(业务层)组件
@Controller: 标识表现层组件
对于扫描到的组件, Spring 有默认的命名策略: 使用非限定类名, 第一个字母小写. 也可以在注解中通过 value 属性值标识组件的名称
当在组件类上使用了特定的注解之后, 还需要在 Spring 的配置文件中声明
base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类.
当需要扫描多个包时, 可以使用逗号分隔.
如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern 属性过滤特定的类,示例:
AOP 的好处
AOP 术语
接口不变。写一个实现类ArithmeticCalculatorImpl.java 这个实现类只关注业务,没有需要打印的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package
com.spring.aop.helloworld;
public
class
ArithmeticCalculatorImpl
implements
ArithmeticCalculator{
@Override
public
int
add(
int
i,
int
j) {
int
result = i + j;
return
result;
}
@Override
public
int
sub(
int
i,
int
j) {
int
result = i - j;
return
result;
}
@Override
public
int
mul(
int
i,
int
j) {
int
result = i * j;
return
result;
}
@Override
public
int
div(
int
i,
int
j) {
int
result = i / j;
return
result;
}
}
|
ArithmeticCaculatorLogginProxy.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package
com.spring.aop.helloworld;
import
java.lang.reflect.InvocationHandler;
import
java.lang.reflect.Method;
import
java.lang.reflect.Proxy;
import
java.util.Arrays;
public
class
ArithmeticCaculatorLogginProxy {
//要代理的对象
private
ArithmeticCalculator target;
public
ArithmeticCaculatorLogginProxy(ArithmeticCalculator target){
this
.target = target;
}
public
ArithmeticCalculator getLoggingProxy() {
ArithmeticCalculator proxy =
null
;
//代理对象由哪一个类加载器负责加载
ClassLoader loader = target.getClass().getClassLoader();
//代理对象的类型,即其中有哪些方法
Class[] interfaces =
new
Class[]{ArithmeticCalculator.
class
};
//当调用代理对象其中的方法时,该执行的代码
InvocationHandler h =
new
InvocationHandler() {
/**
* proxy:正在返回的代理对象,一般情况下,在invoke方法中都不适用该对象
* method:正在被调用的方法
* args:调用方法时,传入的参数
*/
@Override
public
Object invoke(Object proxy, Method method, Object[] args)
throws
Throwable {
//下面这句执行的时候又会调用invoke方法,所以会出现死循环导致内存溢出
//System.out.println(proxy.toString());
String methodName = method.getName();
//日志
System.out.println(
"The method "
+ methodName +
" begins with"
+ Arrays.asList(args));
System.out.println(
"Invoke..."
);
//执行方法
Object result = method.invoke(target, args);
//日志
System.out.println(
"The method"
+ methodName +
" ends with "
+ result);
return
result;
}
};
proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
return
proxy;
}
}
|
main方法
1
2
3
4
5
6
7
8
9
|
ArithmeticCalculator target =
new
ArithmeticCalculatorImpl();
ArithmeticCalculator proxy =
new
ArithmeticCaculatorLogginProxy(target).getLoggingProxy();
proxy.add(
1
,
5
);
|
在同一个连接点上应用不止一个切面时, 除非明确指定, 否则它们的优先级是不确定的.
切面的优先级可以通过实现 Ordered 接口或利用 @Order 注解指定.
实现 Ordered 接口, getOrder() 方法的返回值越小, 优先级越高.
若使用 @Order 注解, 序号出现在注解中
声明切面
声明切入点
声明通知
作为了解即可,主要还是关注在sql语句的使用和orm的框架habernate,mybaties
重点:
1,学习如何引用外部资源文件和配置数据源
<context:component-scan base-package="com.hgh.spring.jdbc">context:component-scan>
<context:property-placeholder location="classpath:db.property"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}">property>
<property name="password" value="${jdbc.password}">property>
<property name="jdbcUrl" value="${jdbc.url}">property>
<property name="driverClass" value="${jdbc.driver}">property>
bean>
2,学习使用org.springframework.jdbc.core.JdbcTemplate的一些基本用法,实现增删改查,重点在批量:jdbcTemplate.batchUpdate(sql, list);和BeanPropertyRowMapper实现数据库到java类的映射
@Test
public void testQueryForOne(){
String sql = "select id , last_name,email from employee where id=?";
RowMapper rowMapper = new BeanPropertyRowMapper(Employee.class);
Employee employee = jdbcTemplate.queryForObject(sql, rowMapper, 1);
System.out.println(employee);
}
重点3:使用NamedParameterJdbcTemplate实现别名.
/**
* 可以为参数起名字.
* 1. 好处: 若有多个参数, 则不用再去对应位置, 直接对应参数名, 便于维护
* 2. 缺点: 较为麻烦.
*/
@Test
public void testNamedParameterJdbcTemplate(){
String sql = "insert into employee(email,last_name) values(:email,:last_name) ";
Map map = new HashMap();
map.put("email", "[email protected]");
map.put("last_name", "hgh41213");
namedParameterJdbcTemplate.update(sql, map);
}
aplicationcontext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.hgh.spring.jdbc">context:component-scan>
<context:property-placeholder location="classpath:db.property"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}">property>
<property name="password" value="${jdbc.password}">property>
<property name="jdbcUrl" value="${jdbc.url}">property>
<property name="driverClass" value="${jdbc.driver}">property>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
bean>
<bean id="namedParameterJdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSource">constructor-arg>
bean>
beans>
JDBCTest
package com.hgh.spring.jdbc;
import static org.junit.Assert.*;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
public class JDBCTest {
private ApplicationContext ac = null;
private JdbcTemplate jdbcTemplate=null;
private EmployeeDao employeeDao;
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
{
ac = new ClassPathXmlApplicationContext("aplicationcontext.xml");
jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate");
employeeDao = (EmployeeDao) ac.getBean("employeeDao");
namedParameterJdbcTemplate = (NamedParameterJdbcTemplate) ac.getBean("namedParameterJdbcTemplate");
}
/**
* 可以为参数起名字.
* 1. 好处: 若有多个参数, 则不用再去对应位置, 直接对应参数名, 便于维护
* 2. 缺点: 较为麻烦.
*/
@Test
public void testNamedParameterJdbcTemplate(){
String sql = "insert into employee(email,last_name) values(:email,:last_name) ";
Map map = new HashMap();
map.put("email", "[email protected]");
map.put("last_name", "hgh41213");
namedParameterJdbcTemplate.update(sql, map);
}
/**
* 测试DAO的调用方法
*/
@Test
public void testGetEmployee(){
System.out.println(employeeDao.getEmployee(2));
}
@Test
public void testForOne(){
String sql = "select count(id) from employee";
Long count = jdbcTemplate.queryForObject(sql, Long.class);
System.out.println(count);
}
/**
* 查到实体类的集合
* 注意调用的不是 queryForList 方法
*/
@Test
public void testQueryForList(){
String sql = "SELECT id, last_name, email FROM employee WHERE id < ?";
RowMapper rowMapper = new BeanPropertyRowMapper<>(Employee.class);
List employees = jdbcTemplate.query(sql, rowMapper,5);
System.out.println(employees);
}
/**
* 从数据库中获取一条记录, 实际得到对应的一个对象
* 注意不是调用 queryForObject(String sql, Class requiredType, Object... args) 方法!
* 而需要调用 queryForObject(String sql, RowMapper rowMapper, Object... args)
* 1. 其中的 RowMapper 指定如何去映射结果集的行, 常用的实现类为 BeanPropertyRowMapper
* 2. 使用 SQL 中列的别名完成列名和类的属性名的映射. 例如 last_name lastName
* 3. 不支持级联属性. JdbcTemplate 到底是一个 JDBC 的小工具, 而不是 ORM 框架
*/
@Test
public void testQueryForOne(){
String sql = "select id , last_name,email from employee where id=?";
RowMapper rowMapper = new BeanPropertyRowMapper(Employee.class);
Employee employee = jdbcTemplate.queryForObject(sql, rowMapper, 1);
System.out.println(employee);
}
/**
* 执行批量更新: 批量的 INSERT, UPDATE, DELETE
* 最后一个参数是 Object[] 的 List 类型: 因为修改一条记录需要一个 Object 的数组, 那么多条不就需要多个 Object 的数组吗
*/
@Test
public void testBathUpdate(){
List
EmployeeDao
package com.hgh.spring.jdbc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
@Repository
public class EmployeeDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public Employee getEmployee(Integer id){
String sql ="select id,email,last_name from employee where id=?";
RowMapper rowMapper = new BeanPropertyRowMapper(Employee.class);
Employee employee = jdbcTemplate.queryForObject(sql, rowMapper,id);
return employee;
}
}
Employee
package com.hgh.spring.jdbc;
public class Employee {
private int id;
private String email;
private String lastName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Employee() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Employee [id=" + id + ", email=" + email + ", lastName="
+ lastName + "]";
}
}