1 Spring重要性
Spring是一个家族体系,可以完成JavaEE开发中几乎所有问题!!(Spring可能会一统Java开发的天下)
Spring项目官网:https://spring.io/projects
Spring家族常见的项目如下:
1)Spring Framework (spring框架 IOC AOP 事务管理,SpringMVC等)
2)Spring Security(权限校验)
3)Spring Data( 一统持久层天下 mysql,oracle,mongoDB,solr等 )
4)Spring Boot(简化Spring开发)
5)Spring Cloud(分布式开发)
6)Spring AMQP(整合RabbitMQ 消息队列)
2 Spring(Framework)介绍
1) Spring Core (IOC容器):创建对象,给对象属性赋值
2)Spring AOP(面向切面编程): 事务管理,自定义AOP编程
3)Spring ORM :Spring整合ORM框架(Hibernate/JPA)
4) Spring JDBC : 提供JdbcTemplate的,对Jdbc简单封装
5)Spring Web: Spring整合Web(Servlet,Filter)
6)SpringMVC:Spring提供MVC表现层模块
7)Spring Context: 国际化,事件驱动编程
一、对象的创建及属性赋值
IOC,Inverse Of Control 控制反转
- 把创建对象的权力,由自己创建(new)改为工厂(IOC容器)来创建
- 最终解决的是创建对象的耦合问题。
DI,Denpedency Injection 依赖注入
- 把对象属性赋值的权力,由自己使用硬编码给对象赋值改为工厂(IOC容器)来完成
- 最终解决的是给对象属性赋值的耦合问题。
1 IOC创建对象的步骤:
-
导入spring-contex依赖
-
创建实体类
-
编写bean.xml文件, bean标签
bean标签配置细节
1.bean.xml配置细节代码演示
<?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">
<!--spring的工厂到底创建何种类型的对象,是根据你配置的bean而创建的
id: 给对象的唯一的标识符
name : 一次可以给对象起多个引用的名称。
class: 创建对象的类型
scope: 指定spring创建对象使用单例还是多例模式, 默认是单例(singleton)
init-method: 创建对象前要调用的方法
destroy-method : 销毁对象的时候要调用的方法(销毁对象的时间: 该对象被垃圾回收器回收或者容器关闭),也要求是在单例模式下去使用
lazy-init : 是否使用懒汉模式,默认情况是饿汉模式(容器一旦创建就创建了所有的对象). true采用了懒汉模式. ,仅对于单例模式下才起作用。
-->
<!--<bean id="user" name="user2,user3" scope="prototype" init-method="init" destroy-method="destroyTest" class="com.itheima.entity.User"/>-->
<bean id="user" scope="prototype" init-method="init" destroy-method="destroyTest" class="com.itheima.entity.User"/>
</beans>
2.对应的测试代码
package com.itheima.test;
import com.itheima.entity.User;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppTest {
@Test
public void test01() throws InterruptedException {
//1. 得到spring的容器
/*
ClassPathXmlApplicationContext: 根据类路径去读取bean.xml文件的。
*/
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
//2. 问容器获取user对象。
User user = (User) applicationContext.getBean("user");
System.out.println("创建的对象:"+user);
Thread.sleep(1000);
//关闭容器
applicationContext.close();
}
}
2 springIOC容器的三种类型(几种方式)
有几种类型的容器
- 绝对路径 : FileSystemXmlApplicationContext
- 类路径: ClassPathXMlApplicationContext
- 读取注解类: AnnotationConfigApplicationContext
FileSystemXmlApplicationContext
ClassPathXMlApplicationContext
3.Spring IOC容器创建对象的三种方式
bean.xml
<bean id="person" class="com.itheima.entity.Person"/>
<!--spring的工厂到底创建何种类型的对象,是根据你配置的bean而创建的
id: 给对象的唯一的标识符
name : 一次可以给对象起多个引用的名称。
class: 创建对象的类型
scope: 指定spring创建对象使用单例还是多例模式, 默认是单例(singleton)
init-method: 创建对象前要调用的方法
destroy-method : 销毁对象的时候要调用的方法(销毁对象的时间: 该对象被垃圾回收器回收或者容器关闭),也要求是在单例模式下去使用
lazy-init : 是否使用懒汉模式,默认情况是饿汉模式(容器一旦创建就创建了所有的对象). true采用了懒汉模式. ,仅对于单例模式下才起作用。
-->
<bean id="user" name="user2,user3" scope="prototype" init-method="init" destroy-method="destroyTest" class="com.itheima.entity.User"/>
在resources目录下建立bean_ioc.xml配置
方式一: 利用类无参的构造器创建对象,这种方式是最为常用的。
<bean id="person" class="com.itheima.entity.Person"/>
方式二: 可以利用工厂类的静态方法创建
<bean id="person" class="com.itheima.utils.Factory" factory-method="getBean"/>
方式三: 利用工厂的非静态方法创建
创建工程的对象
<bean id="factory" class="com.itheima.utils.Factory"/>
<bean id="person" factory-bean="factory" factory-method="getPerson"/>
4.给对象的属性注入值
Spring IOC容器依赖注入,所谓DI, 即依赖注入。
- 带参的构造器
- 利用setter方法,使用property标签
- 利用setter方法,简化上面的方式,利用p空间设置。
1.构造方法注入属性值
<!--constructor-arg常用的属性:
name: 指定构造方法形参名字
value: 指定形参的值,实参
type: 默认情况为String类型,
index: 形参的索引值
index: 形参的索引值 -->
<bean id="person" class="com.itheima.entity.Person">
<constructor-arg name="id" value="10" type="int"/>
<constructor-arg name="name" value="狗娃"/>
<constructor-arg name="sex" value="妖"/>
</bean>
<bean id="person2" class="com.itheima.entity.Person">
<constructor-arg index="0" value="狗剩"/>
<constructor-arg index="1" value="男"/>
</bean>
2.使用set方法注入属性值(最常见)
在Person类提供setter方法
<bean id="person" class="com.itheima.entity.Person">
<property name="id" value="110"/>
<property name="name" value="如花"/>
<property name="sex" value="男"/>
</bean>
3.使用p名称空间
注:底层还是利用setter方法给对象的属性赋值,p名称空间就是setter方法的简化版,只不过简化上面的方式。利用p空间设置
1.Person类也需要为属性提供setter方法
<bean id="person" class="com.itheima.entity.Person" p:id="110" p:name="凤姐" p:sex="仙" />
4.给集合属性赋值
属性如果是list、set、map、数组分别使用哪些标签设置属性值?
- list
- set
- map
- array
对象属性如果是集合类型该赋值的方式
<bean id="person2" class="com.itheima.entity.Person2">
<property name="list">
<list>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</list>
</property>
<property name="set">
<set>
<value>10</value>
<value>20</value>
<value>30</value>
</set>
</property>
<property name="map">
<map>
<entry key="凤姐" value="狗娃"/>
<entry key="如花" value="9527"/>
<entry key="碧螺" value="国家"/>
</map>
</property>
<property name="arr">
<array>
<value>10</value>
<value>20</value>
<value>30</value>
</array>
</property>
</bean>
二、基于注解的 IOC配置
必须在配置文件bean.xml 中开启注解扫描
<!--component-scan ioc 注解扫描 这个标签只能扫描: @Respository、 @Service\@Controller、Component这些注解-->
<!-- 开启注解扫描-->
<context:component-scan base-package="com.itheima"/>
01.@Component 创建对象
英 [kəmˈpəʊnənt] 美 [kəmˈpoʊnənt]
n.
组成部分;成分;部件
adj.
成分的;组成的;合成的;构成的
@Component 创建对象加入容器。举例:工具类。
@Controller: 创建对象加入容器。同@Component一样。一般用于表现层的注解。
@Service: 创建对象加入容器。同@Component一样。一般用于业务层(Service)的注解。
@Repository:创建对象加入容器。同@Component一样。 一般用于持久层(Dao)的注解。
@Component注解就相当于 : <bean id="名称" class="类全名"/>
@Component的用法:
1. 我们可以明确对象的名字。 例如: @Component("abc"), 名字为abc
2. 我可以不指定名字,一旦不指定名字, 名字为当前的类名。 比如: User---user
1.创建项目,导入spring-context依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
使用注解开发我们需要使用哪些进行哪些操作?
- 在bean.xml开启注解扫描: <context:component-scan package="">
- 在对应的类上使用@Component注解。
/*
Component注解就相当于 : <bean id="名称" class="类全名"/>
@Component的用法:
1. 我们可以明确对象的名字。 例如: @Component("abc"), 名字为abc
2. 我可以不指定名字,一旦不指定名字, 名字为当前的类名。 比如: User---user
*/
@Component
public class User {
public User() {
System.out.println("创建了user对象...");
}
}
4.配置bean.xml开启IOC注解扫描(<context:component-scan package=“创建对象的注解所在的包”>)
<!-- 开启注解扫描-->
<context:component-scan base-package="com.itheima"/>
5.测试
02. @Autowired 注入数据
-
作用: 注入数据,从IOC容器获取另一个对象来注入,等于ref属性。
-
@Autowired如何注入?
-
根据类型注入
自动去IOC容器查找该类型对应的对象进行注入
-
根据名称注入
如果容器中存在多个相同类型时,会根据字段的名称去注入。
-
注入数据
1.给类的属性注入数据
2.给该方法的形参注入值
//使用 @Autowired的前提:
// 1. spring的容器中必须要先存在指定类型的数据。 @Autowired首先会先根据类型去匹配。
// 2. 如果spring的容器中存在的多个匹配类型的值,那么就会根据属性名与id值进行匹配。
@Autowired
private String username;
/* 给该方法的形参注入值, 注入的规则与给属性注入的规则是一样*/
@Autowired
public void setUsername(String username) {};
bean.xml
<!-- 用于创建一个对象,目前创建的是字符串的对象。-->
<bean id="str" class="java.lang.String">
<constructor-arg value="狗娃"/>
</bean>
<bean id="username" class="java.lang.String">
<constructor-arg value="狗剩"/>
</bean>
<!-- 开启注解扫描-->
<context:component-scan base-package="com.itheima"/>
03.@Qualifier注入数据
@Qualifier注解说明
-
如果想让@Autowired只根据指定的bean实现依赖注入,要配置@Qualifier注解
-
@Qualifier 通常要配合@Autowired一起使用。@Qualifier可以指定使用哪个bean的值
(在纯注解开发中可以单独使用@Qualifier)
@Autowired
@Qualifier("str") //指定使用ioc容器中创建的str对象 然后注入给 name
private String name;
04 @Value 注入数据
@Value注解作用:
- 给简单类型的字段注入值
- 获取配置文件的值
- 加载配置文件:
<context:property-placeholder location=“db.properties”/>
@Value注解说明
- 直接给简单类型的字段赋值(相当于property标签的value属性)
- 获取配置文件值。 (在纯注解开发时候使用)
bean.xm
<!--加载配置文件 : 使用类文件路径查找配置文件
注意: 如果加载的是单个文件的时候,我们可以省略classpath不写
但是后期我们进行ssm整合的时候,我们一次需要加载多个文件的时候,那么就必须要要写上。
-->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 开启注解扫描-->
<context:component-scan base-package="com.itheima"/>
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///db1
jdbc.username=root
jdbc.password=abc123
05 对象的范围与生命周期
注解说明
@Scope 指定使用单例还是多例模式
@PostConstruct 指定创建对象的初始化方法
@PreDestroy 指定销毁对象前的方法
@Lazy 指定是否使用懒汉单例设计模式
<bean id="" class=""
scope="" 使用@Scope注解取代
init-method="" 使用@PostConstruct注解取代
destroy-method="" 使用@PreDestroy注解取代
lazy-init="" 使用@Lazy注解取代
</bean>
三 JdbcTemplate概述与入门
JdbcTemplate是spring提供的一个模板类,它是对jdbc的封装。用于支持持久层的操作。它的特点是:简单、方便
使用jdbctemplate的步骤
- 创建jdbctemplate的对象,并且传入连接池对象。
- 使用update方法执行增删改的语句
使用jdbctemplate的增删改使用哪个方法?
- update(sql, 参数)
- 参数可以使用可变参数,也可以先参数放入到一个Object数组中传递。
01.原生JdbcTemplate
在resources目录下创建druid配置文件db.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///db1
username=root
password=abc123
创建获取数据源的工具类
public class DataSourceUtils {
private static DataSource dataSource;
static{
try {
Properties properties = new Properties();
properties.load(DataSourceUtils.class.getResourceAsStream("/db.properties"));
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static DataSource getDataSource() {
return dataSource;
}
}
测试
public class AppTest {
//jdbctemplate的入门
@Test
public void testJdbcTemp01(){
//1. 创建jdbctemplate对象,并且把连接池对象传入
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceUtils.getDataSource());
//2 准备sql语句
String sql = "insert into account values(null,?,?)";
//3. 执行sql语句
jdbcTemplate.update(sql,"小黄",1000);
}
}
02.spring IOC管理JdbcTemplate对象
1 db2.properties文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///db1
jdbc.username=root
jdbc.password=abc123
2编写bean.xml
<?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.xsd">
<!--加载配置文件-->
<!--加载配置文件 : 使用类文件路径查找配置文件
注意: 如果加载的是单个文件的时候,我们可以省略classpath不写
加载多个文件的时候,那么就必须要要写上。
-->
<context:property-placeholder location="classpath:db2.properties"/>
<!-- 创建了jdbctemplate的对象-->
<bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--rel: 代表了引用指定的对象-->
<property name="dataSource" ref="db"/>
</bean>
<!-- 创建连接池的对象-->
<bean id="db" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
3测试
public class AppTest2 {
@Test
public void testJdbcTemp01(){
//1 创建spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbctemplate");
//2 准备sql语句
String sql = "insert into account values(null,?,?)";
//3. 执行sql语句
jdbcTemplate.update(sql,"小小",1000);
//执行修改
sql = "update account set name=? where id = ?";
Object[] param = {"大大",5};
jdbcTemplate.update(sql,param);
//删除
sql = "delete from account where id = ?";
jdbcTemplate.update(sql,5);
}
}
03.JdbcTemplate完成查询
- 使用jdbctemplate完成查询
- 能够使用rowmapper结果处理器与BeanPropertyRowMapper结果处理器
-
查询一个对象使用哪个方法?
- queryForObject(String sql, RowMapper rowMapper,@Nullable Object… args)
-
查询多个对象使用哪个方法?
- query(String sql, RowMapper rowMapper)
01.RowMapper结果处理器
RowMapper单个对象
//查询单个对象
@Test
public void test01(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
JdbcTemplate jdbctemplate = (JdbcTemplate) applicationContext.getBean("jdbctemplate");
String sql = "select * from account where id = ?";
Account account = jdbctemplate.queryForObject(sql, new RowMapper<Account>() {
//查询的时候,遍历到每一行都会调用一次mapRow的方法,并且把结果封装到了resultSet给你。
@Override
public Account mapRow(ResultSet rs, int i) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getInt("money"));
return account;
}
}, 4);
System.out.println("查询到的对象:"+ account);
}
RowMapper多个对象
//查询多个
@Test
public void test02(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
JdbcTemplate jdbctemplate = (JdbcTemplate) applicationContext.getBean("jdbctemplate");
String sql = "select * from account";
List<Account> list = jdbctemplate.query(sql, new RowMapper<Account>() {
//查询的时候,遍历到每一行都会调用一次mapRow的方法,并且把结果封装到了resultSet给你。
@Override
public Account mapRow(ResultSet rs, int i) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getInt("money"));
return account;
}
});
System.out.println("查询到的对象:"+ list);
}
02.BeanPropertyRowMapper
单个对象查询
//查询单个对象 使用BeanPropertyRowmapper去实现。
@Test
public void test03(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
JdbcTemplate jdbctemplate = (JdbcTemplate) applicationContext.getBean("jdbctemplate");
String sql = "select * from account where id = ?";
Account account = jdbctemplate.queryForObject(sql,new BeanPropertyRowMapper<Account>(Account.class), 4);
System.out.println("查询到的对象:"+ account);
}
多个对象的查询
//查询多个对象 : 使用BeanPropertyRowmapper去实现。
@Test
public void test04() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
JdbcTemplate jdbctemplate = (JdbcTemplate) applicationContext.getBean("jdbctemplate");
String sql = "select * from account";
List<Account> list = jdbctemplate.query(sql, new BeanPropertyRowMapper<Account>(Account.class));
System.out.println("查询到对象:"+ list);
}
四 spring IOC案例(xml版本)
01 (xml版本)
编写dao与service层,使用spring管理dao与service、jdbctemplate、连接池对象,实现查询所有联系人。
1 配置pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>day43_spring02_1jdbctemplate</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--jdbctemplate的核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--测试
-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
</dependencies>
</project>
2 开发代码
实体类
package com.itheima.entity;
public class Account {
private int id;
private String name;
private int money;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
编写持久层
- dao接口
package com.itheima.dao;
import com.itheima.entity.Account;
import java.util.List;
public interface AccountDao {
List<Account> findAll();
}
- dao实现类
package com.itheima.dao.impl;
import com.itheima.dao.AccountDao;
import com.itheima.entity.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
public class AccountDaoImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
@Override
public List<Account> findAll() {
String sql = "select * from account";
return jdbcTemplate.query(sql,new BeanPropertyRowMapper<Account>(Account.class));
}
}
编写业务层
- service接口
package com.itheima.service;
import com.itheima.entity.Account;
import java.util.List;
public interface AccountService {
List<Account> findAll();
}
-
service实现类
package com.itheima.service.impl; import com.itheima.dao.AccountDao; import com.itheima.entity.Account; import com.itheima.service.AccountService; import java.util.List; public class AccountServiceImpl implements AccountService { private AccountDao accountDao; @Override public List<Account> findAll() { return accountDao.findAll(); } public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } }
编写bean.xml
<?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.xsd">
<!--加载配置文件-->
<context:property-placeholder location="classpath:db2.properties"/>
<!--创建dao的对象-->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbctemplate"/>
</bean>
<!--创建service的对象-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!--由于dao维护了一个jdbctemplate成员变量,所以需要注入-->
<bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 创建一个连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
编写测试类
package com.itheima.test;
import com.itheima.entity.Account;
import com.itheima.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class AppTest {
@Test
public void test01(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
List<Account> list = accountService.findAll();
System.out.println(list);
}
}
02 xml与注解混合版本(最为常用)
1.使用xml配置方式,完成了查询客户列表数据的案例。有点小激动啊
2.等等。在spring IOC中我们不是还学习了注解配置方式吗?要是用注解要怎么实现呢?
3.xml与注解混合使用案例实现思路:
把我们自定义的对象(客户service、客户dao),使用注解方式配置
把第三方对象(JdbcTemplate、DataSource),继续使用xml方式配置
案例
1 dao实现类
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public List<Account> findAll() {
String sql = "select * from account";
return jdbcTemplate.query(sql,new BeanPropertyRowMapper<Account>(Account.class));
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
2 service实现类
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public List<Account> findAll() {
return accountDao.findAll();
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
}
3 配置bean.xml
<?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.xsd">
<!--加载配置文件-->
<context:property-placeholder location="classpath:db2.properties"/>
<!--由于dao维护了一个jdbctemplate成员变量,所以需要注入-->
<bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 创建一个连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--开启注解扫描-->
<context:component-scan base-package="com.itheima"/>
</beans>
4 db2.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///db1
jdbc.username=root
jdbc.password=root
5 测试
public class AppTest {
@Test
public void test01(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
List<Account> list = accountService.findAll();
System.out.println(list);
}
}
03.完全注解基础版本
- 编写一个配置类用于取代bean.xml文件。
- 在类上添加@Configuration注解与@ComponentScan注解用于做包扫描
- 使用@Bean在方法上,用于创建jdbcTemplate对象与数据源对象
@Configuration : 该注解的作用代表了该类是一个配置类,用于取代bean.xml文件的。
@PropertySource(“classpath:db2.propertes”) 用于指定加载配置文件的。
@ComponentScan(“com.itheima”) : 扫描包
@Bean(“dataSource”): 方法上一旦添加 @Bean(“dataSource”)注解,那么该方法会自 动执行,并且把该方法的返回值存储到容器中。
编写配置类
/*
@Configuration : 该注解的作用代表了该类是一个配置类,用于取代bean.xml文件的。
@PropertySource("classpath:db2.propertes") : 用于指定加载配置文件的。
@ComponentScan("com.itheima") : 扫描包
@Bean("dataSource"): 方法上一旦添加 @Bean("dataSource")注解,那么该方法会自动执行,并且把该方法的返回值存储到容器中。
*/
@Configuration
@PropertySource("classpath:db2.properties")
@ComponentScan("com.itheima")
public class SpringConfiguration {
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public JdbcTemplate createJdbcTeamplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean("dataSource")
public DataSource createDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
测试
public class AppTest {
@Test
public void test01(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
List<Account> list = accountService.findAll();
System.out.println(list);
}
}
五 Spring整合Junit
01.基于完全xml版本整合
配置pom.xml
<!--spring的测试包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--测试
-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
编写测试类
/*
@Runwith : 指定测试的时候使用spring的测试类创建容器。
@ContextConfiguration: 加载指定配置文件
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:bean.xml")
public class AppTest {
@Autowired
private AccountService accountService;
@Test
public void test01(){
List<Account> list = accountService.findAll();
System.out.println(list);
}
}
02.基于完全注解版本整合
配置pom.xml
<!--导入spring测试包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--测试
-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
编写配置类
/*
@Configuration : 该注解的作用代表了该类是一个配置类,用于取代bean.xml文件的。
@PropertySource("classpath:db2.propertes") : 用于指定加载配置文件的。
@ComponentScan("com.itheima") : 扫描包
@Bean("dataSource"): 方法上一旦添加 @Bean("dataSource")注解,那么该方法会自动执行,并且把该方法的返回值存储到容器中。
*/
@Configuration
@PropertySource("classpath:db2.properties")
@ComponentScan("com.itheima")
public class SpringConfiguration {
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public JdbcTemplate createJdbcTeamplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean("dataSource")
public DataSource createDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AppTest {
@Autowired
private AccountService accountService;
@Test
public void test01(){
List<Account> list = accountService.findAll();
System.out.println(list);
}
}
六 动态代理两种实现方式
01基于接口动态代理
使用proxy类实现动态代理,代理ContactService的所有方法,要求所有的方法开始执行前做日志记录。
proxy实现动态代理,要求被代理对象必须要实现接口。
public class FactoryUtil {
//该方法可以测试AccountService的实现类的代理对象,当执行代理对象的所有方法之前我们都需要打印出当前的系统时间。
public static AccountService getAccountServiceProxy(){
return (AccountService) Proxy.newProxyInstance(FactoryUtil.class.getClassLoader(),new Class[]{AccountService.class},new InvocationHandler(){
/*
proxy: 当前的代理对象
method: 代表了当前要执行的方法。
args: 当前执行的方法的实参。
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
System.out.println("执行"+method.getName()+"方法的时间:"+simpleDateFormat.format(new Date()));
//让原始对象(被代理对象执行了原始的方法)
//从spring容器中获取AccountService的被代理对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
//执行当前的方法
Object result = method.invoke(accountService, args);
return result;
}
});
}
}
02 Enhancer实现动态代理(CGLIB)
使用proxy类实现动态代理,代理ContactService的所有方法,要求所有的方法开始执行前做日志记录。
要求被代理的对象所属类可以没有实现任何借口,只需要要求该类不是final修饰的即可。
/*
cglib代理模式的核心类:
1. Enhancer
*/
public class FactoryUtil2 {
public static AccountService getAccountServiceProxy(){
return (AccountService) Enhancer.create(AccountServiceImpl.class, new MethodInterceptor() {
/*
Object: 当前的代理对象
method: 当前要执行的方法
objects: 当前要执行方法所需要的参数
methodProxy: 当前的代理方法的的对象
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("执行"+ method.getName()+"当前打开了事务");
//执行原始的方法
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Object accountService = context.getBean("accountService");
Object result = method.invoke(accountService, objects);
System.out.println("执行"+method.getName()+"完毕,马上已经提交事务");
return result;
}
});
}
}
02 Enhancer实现动态代理(CGLIB)
使用proxy类实现动态代理,代理ContactService的所有方法,要求所有的方法开始执行前做日志记录。
要求被代理的对象所属类可以没有实现任何借口,只需要要求该类不是final修饰的即可。
/*
cglib代理模式的核心类:
1. Enhancer
*/
public class FactoryUtil2 {
public static AccountService getAccountServiceProxy(){
return (AccountService) Enhancer.create(AccountServiceImpl.class, new MethodInterceptor() {
/*
Object: 当前的代理对象
method: 当前要执行的方法
objects: 当前要执行方法所需要的参数
methodProxy: 当前的代理方法的的对象
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("执行"+ method.getName()+"当前打开了事务");
//执行原始的方法
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Object accountService = context.getBean("accountService");
Object result = method.invoke(accountService, objects);
System.out.println("执行"+method.getName()+"完毕,马上已经提交事务");
return result;
}
});
}
}