文章目录
- 1.类耦合:import,new class
- 2.接口解耦:import,new impl
- 3.配置文件+反射解耦:classpath
- 4.单例工厂:class.forName
- 5.ioc入门案例:容器中获取ac.getbean(" ")
- 6.spring的工厂结构:接口是I
- 7.bean标签属性:scope=,ac=
- 8.bean标签生命周期:多例工厂对象创建出来就完事了,无法拿或管理。单例工厂放map中可管理bean
- 9.创建对象的3种方式:getBean
- 10.spring的依赖注入:IOC只是对于依赖进行解耦,降低了耦合,但是我们的代码中还是存在依赖的
- 11.配置文件:pom.xml,applicationContext.xml
- 12.service:AccountService.java,AccountServiceImpl.java
- 13.dao:AccountDao.java,AccountDaoImpl.java
- 14.test:AccountServiceTest.java
- 15.使用注解的方式装配bean:component-scan
- 16.常用注解:Autowired
- 17.纯注解开发:Configuration
- 18.spring整合junit:两个注解
- 19.单例:节省资源
1.类耦合:import,new class
jdbc template 就是spring对jdbc的封装。
以前没用接口,实现类如下。
如下层与层耦合,如果要对如上UserService.java功能升级,那么涉及的这个java文件需要重新编译打包部署安装。
2.接口解耦:import,new impl
所以要面向接口编程,将上面UserService.java中class改为interface,如下实现接口。
如下只要更改实现类就行(还是要改代码)。
3.配置文件+反射解耦:classpath
功能更改,改上面配置文件,将如上UserServiceImpl改成UserServiceImpl2就行,java代码不动就不需要重新编译和打包,重启服务器,重新读取配置文件就行。
4.单例工厂:class.forName
所有dao和service对象创建对于反射机制来说,可做出一个工具类
如下,getInstance是第二行自定义的方法。
如上工厂用反射每次创建的对象都不一样,是多例的,某些情况下需要单例如下,每次创建对象都是同一个存在集合中后期调用。
5.ioc入门案例:容器中获取ac.getbean(" ")
<!--IOC相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<?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 definitions here -->
</beans>
如下在resources文件夹下创建,代替beans.properties。
6.spring的工厂结构:接口是I
ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
BeanFactory:什么时候使用,什么时候创建对象。
7.bean标签属性:scope=,ac=
如下applicationContext.xml,init-method
(指定bean被创建时调用的方法,用来初始化),destroy-method
(指定bean被销毁时调用的方法)。
如下多例属性生效。
8.bean标签生命周期:多例工厂对象创建出来就完事了,无法拿或管理。单例工厂放map中可管理bean
如下多例是没有保存对象。
单例模式
:工厂创建时就创建对象并执行init-method。工厂销毁时,bean也会被消毁,执行destory-method方法。
多例模式
:从工厂中获取对象时才会执行init-method。工厂销毁时,bean不会被消毁,不会执行destory-method方法,垃圾回收机制自己回收。
9.创建对象的3种方式:getBean
10.spring的依赖注入:IOC只是对于依赖进行解耦,降低了耦合,但是我们的代码中还是存在依赖的
例如service需要dao层的对象。我们的对象创建交给了spring管理,那么对象的依赖也交给了spring管理。简单的说,spring给对象的属性设置值就叫做依赖注入
。
如下在applicationContext.xml中。
11.配置文件:pom.xml,applicationContext.xml
暂不写servlet,只写service和dao,service要提供增删改查的方法,并且每个service里调用相应的dao实现对数据库真正的
增删改查操作。service和dao层之间依赖的调用通过spring配置方式调用
,包括service和dao层对象的创建交给spring去做,不是我们之前new的方式了。new一个maven工程。
//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>spring_day02_01</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- ioc相关 spring版本一致-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- jdbcTemplate spring版本一致-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!-- 德鲁伊连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
//applicationContext.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">
<!-- 装配service对象到spring容器 -->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 装配dao对象到spring容器 -->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!--
JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
采用构造方式注入连接池对象,
-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
</bean>
<!-- 装配德鲁伊连接池对象
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName();
dataSource.setUrl();
dataSource.setUsername();
dataSource.setPassword();
根据以前如上写的java代码,我们此处可以使用set注入方式,给属性赋值
-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="password" value="root"></property>
<property name="username" value="root"></property>
<property name="url" value="jdbc:mysql://localhost:3306/spring_day02"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
</beans>
12.service:AccountService.java,AccountServiceImpl.java
package com.itheima.service;
import com.itheima.domain.Account;
public interface AccountService {
public void add(Account account);
public void deleteById(int id);
public void update(Account account);
public Account findAccountById(int id);
}
package com.itheima.service.impl;
import com.itheima.dao.AccountDao;
import com.itheima.domain.Account;
import com.itheima.service.AccountService;
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao ; //只声明,没有new,spring创建AccountServiceImpl时应给accountDao赋值,依赖注入提供set方法
public AccountDao getAccountDao() {
return accountDao;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void add(Account account) {
accountDao.add(account);
}
@Override
public void deleteById(int id) {
accountDao.deleteById(id);
}
@Override
public void update(Account account) {
accountDao.update(account);
}
@Override
public Account findAccountById(int id) {
Account account = accountDao.findAccountById(id);
return account;
}
}
13.dao:AccountDao.java,AccountDaoImpl.java
package com.itheima.dao;
import com.itheima.domain.Account;
public interface AccountDao {
void add(Account account);
void deleteById(int id);
void update(Account account);
Account findAccountById(int id);
}
package com.itheima.dao.impl;
import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.dao.AccountDao;
import com.itheima.domain.Account;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.annotation.PostConstruct;
public class AccountDaoImpl implements AccountDao {
private JdbcTemplate jdbcTemplate ; //也要spring注入,加入set方法
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void add(Account account) {
String sql = "insert into account values(?,?,?)"; //mybatis才用#
jdbcTemplate.update(sql,account.getId(),account.getName(),account.getMoney());
}
@Override
public void deleteById(int id) {
String sql = "delete from account where id = ?";
jdbcTemplate.update(sql,id);
}
@Override
public void update(Account account) {
String sql = "update account set money = ? where id = ?";
jdbcTemplate.update(sql,account.getMoney(),account.getId());
}
@Override
public Account findAccountById(int id) {
String sql = "select * from account where id = ?";
Account account = null;
try {
account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), id);
} catch (DataAccessException e) {
e.printStackTrace();
}
return account;
}
}
14.test:AccountServiceTest.java
package com.itheima.service;
import com.itheima.domain.Account;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AccountServiceTest {
private AccountService accountService;
@Before
public void setUp() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
accountService = (AccountService) ac.getBean("accountService");
}
@Test
public void add() {
Account account = new Account();
account.setId(4);
account.setName("wuyifan");
account.setMoney(250);
accountService.add(account); //数据库中增加一行
}
@Test
public void deleteById() {
}
@Test
public void update() {
}
@Test
public void findAccountById() {
Account account = accountService.findAccountById(1);
System.out.println(account);
}
}
findAccountById执行结果如下。
15.使用注解的方式装配bean:component-scan
以前xml方式通过bean标签装配bean。
Component:相当于xml配置的< bean > < bean />标签。注解的value属性值相当于bean标签的id属性。
16.常用注解:Autowired
16.1 用于创建对象的
如下都在applicationContext.xml中。
如下4个注解都一样。
16.2 用于注入数据的
如下在AccountServiceImpl.java中。
16.3 用于改变作用范围的
17.纯注解开发:Configuration
要删除applicationContext.xml,需要一个.java文件即配置类替代下面三个功能。
用SpringConfig.java和JdbcConfig.java替换了applicationContext.xml。
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
/*
* 纯注解开发的步骤: 1.需要一个配置类存放xml中的配置
2.配置注解扫描的包
3.引入外部配置文件
4.创建jdbcTemplate和DataSource数据源
*/
@Configuration //声明当前类是一个配置类,用来替代xml配置。
@ComponentScan("com.itheima") //配置ioc注解的包扫描
@Import(JdbcConfig.class) //导入其他的配置类,JdbcConfig上面不用写@Configuration了
public class SpringConfig {
}
package com.itheima.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
@PropertySource("classpath:jdbc.properties") //加载外部的配置文件
public class JdbcConfig {
/**
* 1.给基本属性注入值,@Value 注解
* 值应该读取配置文件中的内容, ${jdbc.url}
*/
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.driverClass}")
private String driverClass;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* @Bean: 将方法的返回值作为对象,装配到spring容器
* 里面value属性就是bean的id
* 如果不写value属性,那么默认方法名作为bean的唯一标识
*/
@Bean
public DataSource dataSource1(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setUrl(url);
dataSource.setDriverClassName(driverClass);
return dataSource;
}
// @Qualifier: 可以单独使用在方法的变量上,也可以省略
@Bean("jdbcTemplate")
public JdbcTemplate jdbcTemplate( DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
return jdbcTemplate;
}
}
18.spring整合junit:两个注解
1、应用程序的入口
main方法
2、junit单元测试中,没有main方法也能执行
junit集成了一个main方法
该方法就会判断当前测试类中有哪些@Test注解
junit就让有Test注解的方法执行
3、junit不会管我们是否采用spring框架
在执行测试方法时,junit根本不知道我们是不是使用了spring框架
所以也就不会为我们读取配置文件/配置类创建spring核心容器
4、由以上三点可知
当测试方法执行时,没有Ioc容器,就算写了Autowired注解,也无法实现注入
package com.itheima.service;
import com.itheima.config.SpringConfig;
import com.itheima.domain.Account;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.swing.*;
@RunWith(SpringJUnit4ClassRunner.class) //配置spring提供的运行器,自动创建spring容器ac,
//但是需要注意,容器的创建需要依赖配置文件或者说配置类
@ContextConfiguration(classes = SpringConfig.class) //告诉spring的运行器,配置文件
//或者配置类的位置和名字:classes用来配置配置类的,value属性用来配置xml配置文件的位置的
public class AccountServiceTest {
@Autowired
private AccountService accountService;
// @Before
// public void setUp() throws Exception {
// // ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
// //通过解析配置类的方式来获取spring容器
// ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
// accountService = (AccountService) ac.getBean("accountService");
// Object dataSource = ac.getBean("dataSource1");
// System.out.println(dataSource);
// }
// 每次测试spring时都要获取核心容器ac,这个ac每次创建麻烦,每次测试时注重下面方法测试就好了,
// 这个容器交给别人创建就好了,所以spring整合junit目的帮我们创建spring容器。
@Test
public void add() {
Account account = new Account();
account.setId(4);
account.setName("wuyifan");
account.setMoney(250);
accountService.add(account);
}
@Test
public void deleteById() {
}
@Test
public void update() {
}
@Test
public void findAccountById() {
Account account = accountService.findAccountById(1);
System.out.println(account);
}
}
findAccountById执行结果如下:
用于创建对象的注解。
用于注入属性的注解。
19.单例:节省资源
package com.itheima.signleton;
public class Singleton {
/**
* 单例模式: 一个类创建的对象只能有一个。 优势:节省资源
* 1.这个对象不能被new ,构造方法私有化
* 2.必须提供一个静态方法,用来创建当前类的对象。
* 3.声明一个变量用来保存之前创建的对象。
*
* 单例只能使用在没有 线程安全的情况下。
*
* 存在线程安全问题前提条件:
* 1.多线程并发
* 2.访问同一资源。涉及到对于资源的修改。
*/
private Singleton(){
}
private static Singleton singleton = null;
public static Singleton getInstance(){
if(singleton==null){
singleton = new Singleton();
}
return singleton;
}
}