maven/spring01、02
背景
降低程序耦合性
直接new对象, 当类不存在时, 代码就会编译错误 - 耦合性高
降低耦合性:
- 通过反射的方式, 传递的是类的全限定类名字符串
- 将全限定类名通过配置文件的方式读取到程序中
properties xml
配置文件写法: key = value
解决方案: 提供工厂类来解决, 单例模式
SpringIOC: Inversion Of Control 反转控制
ApplicationContext:
对象单例模式, 立即加载, 初始化容器的时候, 就已经将容器中注册的对象全部创建好
BeanFactory: - 了解
延迟加载, 当程序根据id来获得对象的时候, 才创建对象
使用spring框架
- 依赖jar包 spring-context
- 配置文件 <bean id class>
- 使用核心容器 ApplicationContext getBean
spring核心容器管理[创建]对象的三种方式
直接调用构造器※
空参构造器
通过空参构造器的方式创建对象
<!-- bean标签就是在spring核心容器中添加对象
id/name: 对象的唯一标识
class: 对象的全限定类名
-->
<!-- 通过空参构造器的方式来创建对象 -->
<bean id="user" class="com.zzxx.domain.User"/>
<bean id="user1" class="com.zzxx.domain.User"/>
public void test01() {
// 1.打开 spring 核心容器
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
// 2.向核心容器索要对象
User user = (User) ac.getBean("user");
System.out.println(user);
User user1 = ac.getBean("user", User.class);
System.out.println(user1);
// 仅在容器中只有一个User类型的对象时可用
User user2 = ac.getBean(User.class);
System.out.println(user2);
}
有参构造器
通过指定有参构造器的方式创建对象
public AccountServiceImpl(AccountDao ac, String name) {
this.ac = ac;
}
<!-- 调用指定构造器方式来创建对象,
好处: 在创建对象时, 必须指定具体的参数
问题: 改变了创建对象的方式
-->
<bean id="accountService" class="com.zzxx.service.impl.AccountServiceImpl">
<!-- constructor-arg 构造器参数
name: 构造器的参数名
index: 构造器中的参数索引
type: 构造器中的参数类型 == 自动识别类型
======以上三个都是为了确定参数的
value: 传递的实际参数值
ref: 实际传递的参数对象, 对象在spring容器中的唯一标识
-->
<constructor-arg name="name" index="1" value="张张" />
<constructor-arg name="ac" index="0" ref="accountDao"/>
</bean>
静态工厂
- 准备一个工厂类
- 工厂类中提供一个静态方法 - 获得User对象
public class UserFactory {
// 静态工厂方法
public static User getInstance() {
return new User(1, "张张");
}
- 容器中注册
<!-- 通过静态工厂来创建对象
class: 指定的是工厂类的全限定类名
factory-method: 静态方法
-->
<bean id="user1" class="com.zzxx.factory.UserFactory" factory-method="getInstance"/>
public void testStaticFactory() {
// 1.打开 spring 核心容器
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
// 2.向核心容器索要对象
User user1 = ac.getBean("user1", User.class);
System.out.println(user1);
}
工厂方法
- 准备一个工厂类
- 工厂类中提供一个成员方法 - 获得User对象
public class UserFactory {
// 工厂方法
public User init() {
return new User(1);
}
}
- 容器中注册
<!-- 通过工厂方法来创建对象
class: 要创建的类的全限定类名
factory-bean: 工厂对象
factory-method: 普通的工厂方法
-->
先注册工厂对象
<bean id="factory" class="com.zzxx.factory.UserFactory"/>
<bean id="user2" class="com.zzxx.domain.User"
factory-bean="factory" factory-method="init"/>
bean属性设置
scope:作用域—生命周期※
-
singleton: 默认值, 单例, 容器初始化时创建(初始化容器的时候, 就已经将容器中注册的对象全部创建好), 容器关闭时销毁
-
prototype: 多例, 根据id获得对象时创建, 用GC回收时销毁, destroy-method 失效,例:Struts2框架 XXAction 必须是多例的
-
request: 作用于HttpServletRequest对象
session: 作用于HttpSession对象
<bean id="accountService" class="com.zzxx.service.impl.AccountServiceImpl"
scope="singleton" init-method="init" destroy-method="destroy"
/>
init/destroy-method
init-method: 初始化方法, 创建完对象后调用的方法
destroy-method: 销毁对象之前调用的方法
spring属性注入
set方法注入※
public void setAccountDao(AccountDao ac) {
this.ac = ac;
}
<!-- set方式注入: 就是在调用对象的setXX()方法 -->
<bean id="accountService1" class="com.zzxx.service.impl.AccountServiceImpl">
<!-- property: 要注入的属性
name: 属性名字 看的是setXX方法
value
ref
-->
<property name="accountDao" ref="accountDao" />
</bean>
<bean id="accountDao" class="com.zzxx.dao.impl.AccountDaoImpl"/>
构造函数注入
public User(int id, String name, Date date) {
this.id = id;
this.name = name;
this.date = date;
}
<!-- 构造器注入:提供构造器 -->
<bean id="user4" class="com.zzxx.domain.User">
<constructor-arg name="id" index="0" value="3"/>
<constructor-arg name="name" value="李四" type="java.lang.String"/>
<constructor-arg name="date" ref="now"/>
</bean>
复杂类型注入
private int[] arr;
private List<String> list;
private Map<Integer, String> map;
private Properties properties;
<bean name="user" class="com.zzxx.domain.User">
<!-- 注入数组类型 -->
<!-- 1.如果数组中只有一个元素
直接通过value属性注入
-->
<!-- <property name="arr" value="10" />-->
<!-- 2.如果数组中有多个元素
通过<array>标签注入
值: <value>
引用: <ref>
-->
<property name="arr">
<array>
<value>10</value>
<value>20</value>
<value>30</value>
</array>
</property>
</bean>
<bean name="user1" class="com.zzxx.domain.User">
<property name="list">
<list>
<value>张三</value>
<value>李四</value>
<value>狗剩</value>
</list>
</property>
</bean>
<!-- 给 map 属性赋值 用<map>
每一个元素: <entry>标签
-->
<bean name="user2" class="com.zzxx.domain.User">
<property name="map">
<map>
<entry key="10" value="张三"/>
<entry key="20" value="李四"/>
<entry key="30" value="丫蛋"/>
</map>
</property>
</bean>
<!-- 给 properties 属性赋值 用<props>
每一个元素: <prop>标签 key value[标签体中]
-->
<bean name="user3" class="com.zzxx.domain.User">
<property name="properties">
<props>
<prop key="driver">com.mysql.cj.jdbc.Driver</prop>
<prop key="url">jdbc:mysql:///mybatis</prop>
<prop key="username">root</prop>
<prop key="password">root</prop>
</props>
</property>
</bean>
使用注解配置spring
在配置文件中开启注解扫描
<!-- 开启注解扫描
base-package: 扫描注解的包
指定包下所有的后代包一起扫描
-->
<context:component-scan base-package="com.zzxx"/>
添加注解
@Component("user")
// 设置对象的scope : prototype/singleton
@Scope("singleton")
public class User {
private int id;
@Value("10") // user.setId(10)
public void setId(int id) {
this.id = id;
}
@PostConstruct // 在构造器之后执行 init-method
public void init() {
System.out.println("user init");
}
@PreDestroy // 在销毁之前执行 destroy-method
public void destroy() {
System.out.println("user destroy");
}
}
javax.annotation包中的
@PostConstruct
@PreDestroy
注意: 使用之前需要添加依赖
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
// 将 AccountDaoImpl 对象注册到spring容器中,并且id=accountDao
//@Component("accountDao")
@Repository // dao层对象使用
public class AccountDaoImpl implements AccountDao {
}
// 将当前测试类 和 Spring 容器绑定, 在执行@Test方法时, 默认打开spring容器
@RunWith(SpringJUnit4ClassRunner.class)
// 指定容器的配置文件
@ContextConfiguration(locations = "classpath:beans.xml")
public class AccountDaoTest {
@Autowired
AccountDao dao;
@Test
public void updateTest() {
dao.updateAccount();
}
// Component 不加属性, 就没有id
//@Component
@Service // service层对象使用
//@Controller // web层对象使用
public class AccountServiceImpl implements AccountService {
// 使用AccountDao的方法
@Autowired
private AccountDao ac;
public void update() {
ac.updateAccount();
}
// 将当前测试类 和 Spring 容器绑定, 在执行@Test方法时, 默认打开spring容器
@RunWith(SpringJUnit4ClassRunner.class)
// 指定容器的配置文件
@ContextConfiguration(locations = "classpath:beans.xml")
public class AccountServiceTest {
@Autowired
AccountService service;
@Test
public void updateTest() {
service.update();
}
使用注解配置spring(不使用xml文件)
/**
* 取代beans.xml配置文件
* Configuration:
* 作用: 指定当前类为注解配置类
* 注意: 如果当前类作为AnnotationConfigApplicationContext创建对象的参数时, 注解可以省略
* ComponentScan:
* <context:component-scan base-package="com.zzxx"/>
* 属性: basePackages/value
* Bean: 取代 <bean></bean>
* 作用: 将方法的返回值对象 交给spring容器中
* 方法参数的注入: 效果等同于 Autowired
* 如果容器中有多个参数类型的对象, 可以使用 @Qualifier("ds2") 来指定注入的对象名
* Import: 取代 <import resource=""/>
* 作用: 关联其他的配置类
* PropertySource: 取代 <context:property-placeholder location="classpath:jdbc.properties"/>
* 作用: 读取properties配置文件
* 使用: 借助 Value注解来将读取出来的值注入到配置类中
* @Value("${driver}")
* @author bonnie
**/
@Configuration
@ComponentScan("com.zzxx")
@PropertySource("classpath:jdbc.properties")
public class SpringConfiguration {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public JdbcTemplate createJdbcTemplate(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
@Bean
public DataSource createDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
public class main {
public static void main(String[] args) {
//有多个配置类可以把参数改为扫描多个包
//ApplicationContext ac = new AnnotationConfigApplicationContext("com.zzxx", "config");
ApplicationContext ac=new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = ac.getBean(UserService.class);
User user=new User();
user.setUsername("锅巴");
user.setSex("女");
user.setAddress("杭州");
user.setBirthday(new Date());
userService.addAccount(user);
}
}
spring和junit
添加依赖junit + spring-tes
spring和jdbc
JdbcTemplate
1.将JdbcTemplate注册到spring容器中
jdbcTemplate依赖于连接池
需要注册DataSource
2.注册UserDaoImpl对象
3.将jdbcTemplate 注入到 UserDaoImpl 中
4.注册UserServiceImpl对象