java p46——springIOC

背景

降低程序耦合性

直接new对象, 当类不存在时, 代码就会编译错误 - 耦合性高
降低耦合性:

  1. 通过反射的方式, 传递的是类的全限定类名字符串
  2. 将全限定类名通过配置文件的方式读取到程序中
    properties xml
    配置文件写法: key = value
    解决方案: 提供工厂类来解决, 单例模式

SpringIOC: Inversion Of Control 反转控制

ApplicationContext:
对象单例模式, 立即加载, 初始化容器的时候, 就已经将容器中注册的对象全部创建好
BeanFactory: - 了解
延迟加载, 当程序根据id来获得对象的时候, 才创建对象

使用spring框架

  1. 依赖jar包 spring-context
  2. 配置文件 <bean id class>
  3. 使用核心容器 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>

静态工厂

  1. 准备一个工厂类
  2. 工厂类中提供一个静态方法 - 获得User对象
public class UserFactory {
    // 静态工厂方法
    public static User getInstance() {
        return new User(1, "张张");
    }
  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);
    }

工厂方法

  1. 准备一个工厂类
  2. 工厂类中提供一个成员方法 - 获得User对象
public class UserFactory {
    // 工厂方法
    public User init() {
        return new User(1);
    }
}

  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对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值