七大模块
耦合:程序中的依赖关系。其中一种依赖关系是对象之间的关联性。对象之间关联性越高,维护成本越高。
划分模块的一个准则就是高内聚低耦合
高内聚,低耦合:类内部的关系越紧密越好,类与类之间的关系越少越好。
表现层需要创建业务层的实例来调用业务层的方法,同样业务层也要创建持久层的示例来调用持久层的方法。按照传统开发方法,创建实例都是直接new,一旦更换数据库或者拓展已有业务(新的业务层接口实例),就会影响到原有的代码,需要修改源代码(也就是耦合问题)
解决耦合问题的关键,业务层或持久层的实例不手动直接创建,而是交由第三方(工厂)创建。通过修改工厂的配置文件获取对应的实例,不需要修改原有代码,实现解耦
下面简单举例
dao接口
public interface IAccountDao {
void save();
}
dao实现类
//mysql
public class AccountDaoImpl implements IAccountDao {
@Override
public void save() {
System.out.println("mysql保存用户");
}
}
//oracle
public class AccountDaoOracleImpl implements IAccountDao {
@Override
public void save() {
System.out.println("oracle保存用户");
}
}
service接口
public interface IAccountService {
void save();
}
service实现类
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao = new AccountDaoImpl();
@Override
public void save() {
accountDao.save();
}
}
#dao层
#mysql
AccountDao=com.azure.dao.impl.AccountDaoImpl
#oracle
#AccountDao=com.azure.dao.impl.AccountDaoOracleImpl
#service层
AccountService=com.azure.service.impl.AccountServiceImpl
public class BeanFactory {
/*
读取properties配置文件有两种方式:
1、直接创建properties对象,使用关联配置文件的输入流加载文件数据到properties中;
2、通过ResourceBundle加载配置文件
1)只可以加载properties后缀的配置文件
2)只能加载类路径下的properties配置文件
*/
//读取配置文件并创建对应的对象
//使用泛型,通过传入泛型类型返回对应类型的对象
public static <T> T getBean(String name,Class<T> clazz) {
try {
//读取配置文件数据
ResourceBundle bundle = ResourceBundle.getBundle("instance");
//获取key对应的value。比如AccountDao=com.azure.dao.impl.AccountDaoImpl
String value = bundle.getString(name);
return (T) Class.forName(value).getConstructor().newInstance();//jdk1.9做法
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao = BeanFactory.getBean("AccountDao", IAccountDao.class);
@Override
public void save() {
accountDao.save();
}
}
public class app {
public static void main(String[] args) {
//使用工厂创建service对象
IAccountService accountService = BeanFactory.getBean("AccountService", IAccountService.class);
accountService.save();
}
}
通过修改配置文件即可完成dao或service的转换,不需要修改已有代码
使用工厂类实现三层架构的解耦,其核心思想就是
其核心思想归纳起来就是IOC(Inversion Of Control 控制反转)
下面将创建一个简单的IOC案例
<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.0modelVersion>
<groupId>com.azuregroupId>
<artifactId>day51projects_spring_IOCartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.0.2.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
project>
public class User implements Serializable {
public User(){
//使用无参实例化User对象时都会进入
System.out.println("创建User对象");
}
}
<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="user" class="com.azure.entity.User">bean>
beans>
public class Test01 {
@Test
public void test(){
//创建ioc容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//从容器中获取对象
User user = (User) ac.getBean("user");
System.out.println(user);
}
}
1.FileSystemXmlApplicationContext:加载本地的配置文件
2.ClassPathXmlApplicationContext:加载类路径下的配置文件(重点)
3.AnnotationConfigWebApplicationContext:注解方式开发创建容器
4.WebApplicationContext:web项目中创建容器
5.BeanFactory:使用工厂创建对象
疑问:BeanFactory与ApplicationContext创建容器区别?
BeanFactory 在创建容器时候,没有自动创建对象
ApplicationContext 在创建容器时候,默认自动创建对象。
public class Test02 {
/*1.FileSystemXmlApplicationContext:加载本地的配置文件*/
@Test
public void test_file(){
//获得配置文件的真实路径
String path = "E:\\Java_study\\JavaprojectsIV\\day51projects_spring_IOC\\src\\main\\resources\\bean.xml";
//从容器中获取对象
ApplicationContext ac = new FileSystemXmlApplicationContext(path);
User user = (User) ac.getBean("user");
System.out.println(user);
}
/*2.ClassPathXmlApplicationContext:加载类路径下的配置文件(重点)*/
@Test
public void test_class(){
//类路径下要有bean.xml
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//从容器中获取对象
User user = (User) ac.getBean("user");
System.out.println(user);
}
/*3.AnnotationConfigWebApplicationContext:注解方式开发创建容器*/
@Test
public void test_annotation(){
/*//程序中要有SpringConfig类,表示容器类(相当于bean.xml)
ApplicationContext ac = new AnnotationConfigApplicationContext("SpringConfig.class");
//从容器中获取对象
User user = (User) ac.getBean("user");
System.out.println(user);*/
}
/*4.使用BeanFactory顶级接口创建容器*/
@Test
public void test_factory(){
Resource resource = new ClassPathResource("bean.xml");
BeanFactory factory = new XmlBeanFactory(resource);
User user = (User) factory.getBean("user");//创建User对象
}
}
常用配置
id、class,可选scope、lazy-init、init-method、destroy-method
<bean
id="user"
name="user2,user3"
class="com.azure.entity.User"
scope="prototype"
lazy-init="true"
init-method="init" destroy-method="preDestory">bean>
注意事项:
id和name的作用相同,均是指定对象的名称,用于通过该名称获取ioc容器中的对象。但是形式不同。id不能指定多个名称,name可以指定多个名称。按照实际开发,更常用的是id。
创建工厂类
public class UserFactory {
/*1.通过实例方法返回对象*/
public User createUser(){
System.out.println("工厂实例方法创建一个对象");
return new User();
}
}
配置bean.xml
<bean id="factory" class="com.azure.factory.UserFactory">bean>
<bean id="user" factory-bean="factory" factory-method="createUser">bean>
工厂类中添加静态方法
*2.通过静态方法返回对象*/
public static User createUser_static(){
System.out.println("工厂静态方法创建一个对象");
return new User();
}
配置bean.xml
<bean id="user1" class="com.azure.factory.UserFactory" factory-method="createUser_static"/>
创建实体类对象
public class Student {
private int id;
private String name;
//使用有参构造函数创建对象,实体类必须有有参构造函数
public Student(int id, String name) {
this.id = id;
this.name = name;
}
/*省略toString、getter&setter*/
}
配置bean.xml
常用index、value和ref三个属性
<bean id="student" class="com.azure.entity.Student">
<constructor-arg index="0" value="10">constructor-arg>
<constructor-arg index="1" ref="str">constructor-arg>
bean>
<bean id="str" class="java.lang.String">
<constructor-arg index="0" value="明明">constructor-arg>
bean>
创建实体类对象,并提供set方法给对象属性赋值
配置bean.xml
<bean id="student2" class="com.azure.entity.Student">
<property name="id" value="12">property>
<property name="name" ref="str">property>
bean>
也是调用set方法给对象属性赋值
在spring3.0之后版本才有的,主要目的是为了简化配置
配置bean.xml,配置时要在beans标签中引入xmlns:p="http://www.springframework.org/schema/p"
<bean id="student3" class="com.azure.entity.Student" p:id="168" p:name-ref="str">bean>
实体类,要有set/get方法
配置bean.xml
<bean id="students" class="com.azure.entity.Student">
<property name="list">
<list>
<value>cnvalue>
<value>usavalue>
list>
property>
<property name="set">
<set>
<value>cnvalue>
<value>usavalue>
set>
property>
<property name="map">
<map>
<entry key="cn" value="China"/>
<entry key="usa" value="America"/>
map>
property>
<property name="properties">
<props>
<prop key="cn">Chinaprop>
<prop key="usa">Americaprop>
props>
property>
bean>
添加依赖(pom.xml)
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.30version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.0.2.RELEASEversion>
dependency>
dependencies>
service的实例
public class AccountServiceImpl implements IAccountService {
/*由spring的ioc容器注入dao*/
private IAccountDao accountDao;//先定义dao对象
//注入方法(对应bean.xml中的property标签)
//使用set方法给dao对象赋值!!方法的参数就是ioc容器中保存的dao对象
public void setAccountDao(IAccountDao accountDao) {
this.accountDao=accountDao;
}
@Override
public void save() {
accountDao.save();
}
}
配置bean.xml
<bean id="accountDao" class="com.azure.dao.impl.AccountDaoImpl">bean>
<bean id="accountService" class="com.azure.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao">property>
bean>
测试类
public class app {
public static void main(String[] args) {
//创建容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//使用工厂创建service对象
IAccountService accountService = ac.getBean("accountService", IAccountService.class);
accountService.save();
}
}
该改造方法的思路是
所谓的注入依赖,就是给对象属性赋值
<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.0modelVersion>
<groupId>com.azuregroupId>
<artifactId>day52projects_spring_xmlartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.0.2.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.0.2.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>5.0.2.RELEASEversion>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.10version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.32version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
project>
public class account {
private int accountId;
private int uid;
private double money;
/*省略无参、有参、toString、getter&setter*/
}
public interface IAccountDao {
//添加
void save(Account account);
//更新
void update(Account account);
//删除
void delete(int aid);
//查询
List<Account> findAll();
}
public class AccountDaoImpl implements IAccountDao {
private JdbcTemplate jdbcTemplate;
/*使用SpringIOC容器注入jdbcTemplate对象,提供set方法*/
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void save(Account account) {
jdbcTemplate.update("insert into account values (null,?,?)",account.getUid(),account.getMoney());
}
@Override
public void update(Account account) {
jdbcTemplate.update("update account set uid=?,money=? where accountId=?",account.getUid(),account.getMoney(),account.getAccountId());
}
@Override
public void delete(int id) {
jdbcTemplate.update("delete from account where accountId=?",id);
}
@Override
public List<Account> findAll() {
return jdbcTemplate.query("select * from account",new BeanPropertyRowMapper<>(Account.class));
}
}
public interface IAccountService {
//添加
void save(Account account);
//更新
void update(Account account);
//删除
void delete(int id);
//查询
List<Account> findAll();
}
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
/*使用SpringIOC容器注入dao对象,提供set方法*/
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void save(Account account) {
accountDao.save(account);
}
@Override
public void update(Account account) {
accountDao.update(account);
}
@Override
public void delete(int id) {
accountDao.delete(id);
@Override
public List<Account> findAll() {
return accountDao.findAll();
}
}
<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.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver">property>
<property name="url" value="jdbc:mysql:///mybatis?characterEncoding=utf8">property>
<property name="username" value="root">property>
<property name="password" value="root">property>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
bean>
<bean id="accountDao" class="com.azure.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate">property>
bean>
<bean id="accountService" class="com.azure.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao">property>
bean>
beans>
public class WebApp {
/*测试类中创建容器获取service对象*/
private ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
private IAccountService accountService = (IAccountService) ac.getBean("accountService");
@Test
public void save() {
Account account = new Account();
account.setUid(46);
account.setMoney(99D);
accountService.save(account);
}
@Test
public void update() {
Account account = new Account();
account.setAccountId(1);
account.setUid(46);
account.setMoney(99D);
accountService.update(account);
}
@Test
public void delete() {
accountService.delete(4);
}
@Test
public void findAll() {
System.out.println(accountService.findAll());
}
}
将数据库连接设置放在jdbc.properties中,bean.xml里面加载文件。
标签加载properties文件;注意写法
<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/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}}">property>
<property name="url" value="${jdbc.url}">property>
<property name="username" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
bean>
<bean id="accountDao" class="com.azure.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate">property>
bean>
<bean id="accountService" class="com.azure.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao">property>
bean>
beans>