spring 复习

Posted on 2020-11-04 09:44  锦喵卫指挥使  阅读(87)  评论(0编辑  收藏  举报

目录

===================================================

01.Spring框架简介


01.spring课程四天安排


02.今日课程内容介绍


03.spring概述


04.spring发展历程


05.spring的优势


06.spring的体系结构

===================================================

02.程序间耦合


编写jdbc的工程代码用于分析程序的耦合

<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.spring</groupId>
	<artifactId>hello</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<packaging>jar</packaging>

	<dependencies>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.6</version>
		</dependency>
	</dependencies>

</project>
/**
 * 程序的耦合
 *      耦合:程序间的依赖关系
 *          包括:
 *              类之间的依赖
 *              方法间的依赖
 *      解耦:
 *          降低程序间的依赖关系
 *      实际开发中:
 *          应该做到:编译期不依赖,运行时才依赖。
 *      解耦的思路:
 *          第一步:使用反射来创建对象,而避免使用new关键字。
 *          第二步:通过读取配置文件来获取要创建的对象全限定类名
 *
 */
package com.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class JdbcDemo {

	public static void main(String[] args) throws  Exception{
        //1.注册驱动
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//        Class.forName("com.mysql.jdbc.Driver");

        //2.获取连接
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/easy","root","root");
        //3.获取操作数据库的预处理对象
        PreparedStatement pstm = conn.prepareStatement("select * from account");
        //4.执行SQL,得到结果集
        ResultSet rs = pstm.executeQuery();
        //5.遍历结果集
        while(rs.next()){
            System.out.println(rs.getString("name"));
        }
        //6.释放资源
        rs.close();
        pstm.close();
        conn.close();
    }
}

此中DriverManager.registerDriver(new com.mysql.jdbc.Driver());被代码Class.forName("com.mysql.jdbc.Driver");所替换。为什么呢?因为new com.mysql.jdbc.Driver()编译时候需要包mysql-connector-java,否则编译不通过。而Class.forName("com.mysql.jdbc.Driver")编译时候可以没有jdbc包达到解耦,编译期不依赖,运行时才依赖。

编译期依赖


程序的耦合和解耦的思路分析1


曾经代码中的问题分析

package com.bbb.factory.IAccountDao;

public interface IAccountDao{

	/**
     * 模拟保存账户
     */
    void saveAccount();
}

package com.bbb.factory.IAccountDao.impl;

import com.bbb.factory.IAccountDao.IAccountDao;

public class AccountDao implements IAccountDao{

	public void saveAccount() {
		System.out.println("保存了账户");
	}

}

package com.bbb.factory.IAccountService;

public interface IAccountService {

    /**
     * 模拟保存账户
     */
    void saveAccount();
}

package com.bbb.factory.IAccountService.impl;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountDao.impl.AccountDao;
import com.bbb.factory.IAccountService.IAccountService;

public class AccountService implements IAccountService {
	
	private IAccountDao accountDao = new AccountDao();

	public void saveAccount() {
		
		accountDao.saveAccount();
	}

}

package com.bbb.factory.client;

import com.bbb.factory.IAccountService.IAccountService;
import com.bbb.factory.IAccountService.impl.AccountService;

public class Client {

	public static void main(String[] args) {
		IAccountService as = new AccountService();
		as.saveAccount();
	}

}

可以看到IAccountService as = new AccountService();还有private IAccountDao accountDao = new AccountDao();导致了耦合问题,为了降低程序间的依赖关系,应该对代码进行改造。

编写工厂类和配置文件


工厂模式解耦

accountService=com.bbb.factory.IAccountService.impl.AccountService2
accountDao=com.bbb.factory.IAccountDao.impl.AccountDao
package com.bbb.factory.BeanFactory;

import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class BeanFactory {
	
	private static Properties props;
	

    //使用静态代码块为Properties对象赋值
    static {
        try {
            //实例化对象
            props = new Properties();
            //获取properties文件的流对象
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            props.load(in);
           
        }catch(Exception e){
            throw new ExceptionInInitializerError("初始化properties失败!");
        }
    }
    

    /**
     * 根据Bean的名称获取bean对象
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName){
        Object bean = null;
        try {
            String beanPath = props.getProperty(beanName);
            bean = Class.forName(beanPath).newInstance();//每次都会调用默认构造函数创建对象
        }catch (Exception e){
            e.printStackTrace();
        }
        return bean;
    }

}

package com.bbb.factory.IAccountService.impl;

import com.bbb.factory.BeanFactory.BeanFactory;
import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountDao.impl.AccountDao;
import com.bbb.factory.IAccountService.IAccountService;

public class AccountService2 implements IAccountService {

	private IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao");

	public void saveAccount() {

		accountDao.saveAccount();
	}

}
package com.bbb.factory.client;

import com.bbb.factory.BeanFactory.BeanFactory;
import com.bbb.factory.IAccountService.IAccountService;
import com.bbb.factory.IAccountService.impl.AccountService;

public class Client2 {

	public static void main(String[] args) {
		IAccountService as = (IAccountService) BeanFactory.getBean("accountService");
		as.saveAccount();
	}

}

运行结果:

com.bbb.factory.IAccountService.impl.AccountService2
com.bbb.factory.IAccountDao.impl.AccountDao
保存了账户

分析工厂模式中的问题并改造

package com.bbb.factory.client;

import com.bbb.factory.BeanFactory.BeanFactory;
import com.bbb.factory.IAccountService.IAccountService;
import com.bbb.factory.IAccountService.impl.AccountService;

public class Client3 {

	public static void main(String[] args) {
		
		for (int i = 0; i < 5; i++) {
			IAccountService as = (IAccountService) BeanFactory.getBean("accountService");
			System.out.println(as);
		}
		
	}

}

com.bbb.factory.IAccountService.impl.AccountService2@6d06d69c
com.bbb.factory.IAccountService.impl.AccountService2@7852e922
com.bbb.factory.IAccountService.impl.AccountService2@4e25154f
com.bbb.factory.IAccountService.impl.AccountService2@70dea4e
com.bbb.factory.IAccountService.impl.AccountService2@5c647e05
上面的代码是多例的

工厂模式解耦的升级版

package com.bbb.factory.BeanFactory;

import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class BeanFactory2 {
	
	private static Properties props;
	
	//定义一个Map,用于存放我们要创建的对象。我们把它称之为容器
    private static Map<String,Object> beans;

    //使用静态代码块为Properties对象赋值
    static {
        try {
            //实例化对象
            props = new Properties();
            //获取properties文件的流对象
            InputStream in = BeanFactory2.class.getClassLoader().getResourceAsStream("bean.properties");
            props.load(in);
            
          //实例化容器
            beans = new HashMap<String,Object>();
            //取出配置文件中所有的Key
            Enumeration keys = props.keys();
            //遍历枚举
            while (keys.hasMoreElements()){
                //取出每个Key
                String key = keys.nextElement().toString();
                //根据key获取value
                String beanPath = props.getProperty(key);
                //反射创建对象
                Object value = Class.forName(beanPath).newInstance();
                //把key和value存入容器中
                beans.put(key,value);
            }
           
        }catch(Exception e){
            throw new ExceptionInInitializerError("初始化properties失败!");
        }
    }

    /**
     * 根据bean的名称获取对象
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName){
        return beans.get(beanName);
    }
}

package com.bbb.factory.client;

import com.bbb.factory.BeanFactory.BeanFactory2;
import com.bbb.factory.IAccountService.IAccountService;
import com.bbb.factory.IAccountService.impl.AccountService;

public class Client4 {

	public static void main(String[] args) {
		
		for (int i = 0; i < 5; i++) {
			IAccountService as = (IAccountService) BeanFactory2.getBean("accountService");
			System.out.println(as);
		}
		
	}

}

运行结果:

com.bbb.factory.IAccountService.impl.AccountService2@6d06d69c
com.bbb.factory.IAccountService.impl.AccountService2@6d06d69c
com.bbb.factory.IAccountService.impl.AccountService2@6d06d69c
com.bbb.factory.IAccountService.impl.AccountService2@6d06d69c
com.bbb.factory.IAccountService.impl.AccountService2@6d06d69c

===================================================

03.Spring的 IOC 和 DI


1 ioc的概念和作用


2 spring中的Ioc前期准备


3 spring基于XML的IOC环境搭建和入门

<?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="accountService" class="com.bbb.factory.IAccountService.impl.AccountService3"></bean>

    <bean id="accountDao" class="com.bbb.factory.IAccountDao.impl.AccountDao"></bean>
</beans>
package com.bbb.factory.IAccountService.impl;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountDao.impl.AccountDao;
import com.bbb.factory.IAccountService.IAccountService;

public class AccountService3 implements IAccountService {
	
	private IAccountDao accountDao;

	public void saveAccount() {
		
		accountDao.saveAccount();
	}

}

package com.bbb.factory.client;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountService.IAccountService;

public class Client5 {

	public static void main(String[] args) {
		// 1.获取核心容器对象
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		// 2.根据id获取Bean对象
		IAccountService as = (IAccountService) ac.getBean("accountService");
		IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);

        System.out.println(as);
        System.out.println(adao);
        
        as.saveAccount();
	}

}

运行结果:

十一月 02, 2020 5:17:54 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5a2e4553: startup date [Mon Nov 02 17:17:54 CST 2020]; root of context hierarchy
十一月 02, 2020 5:17:54 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [bean.xml]
com.bbb.factory.IAccountService.impl.AccountService3@475530b9
com.bbb.factory.IAccountDao.impl.AccountDao@1d057a39
Exception in thread "main" java.lang.NullPointerException
	at com.bbb.factory.IAccountService.impl.AccountService3.saveAccount(AccountService3.java:13)
	at com.bbb.factory.client.Client5.main(Client5.java:21)


4 ApplicationContext的三个实现类


5 BeanFactory和ApplicationContext的区别

package com.itheima.ui;

import com.itheima.dao.IAccountDao;
import com.itheima.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 模拟一个表现层,用于调用业务层
 */
public class Client {

    /**
     * 获取spring的Ioc核心容器,并根据id获取对象
     *
     * ApplicationContext的三个常用实现类:
     *      ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)
     *      FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
     *
     *      AnnotationConfigApplicationContext:它是用于读取注解创建容器的,是明天的内容。
     *
     * 核心容器的两个接口引发出的问题:
     *  ApplicationContext:     单例对象适用              采用此接口
     *      它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。
     *
     *  BeanFactory:            多例对象使用
     *      它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。
     * @param args
     */
    public static void main(String[] args) {
        //1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//        ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\Users\\zhy\\Desktop\\bean.xml");
        //2.根据id获取Bean对象
        IAccountService as  = (IAccountService)ac.getBean("accountService");
        IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);

        System.out.println(as);
        System.out.println(adao);
        as.saveAccount();


        //--------BeanFactory----------
//        Resource resource = new ClassPathResource("bean.xml");
//        BeanFactory factory = new XmlBeanFactory(resource);
//        IAccountService as  = (IAccountService)factory.getBean("accountService");
//        System.out.println(as);
    }
}

判断对象是否创建看构造方法。

6 spring中bean的细节之三种创建Bean对象的方式

使用默认构造函数创建
package com.bbb.factory.IAccountService.impl;

import java.util.concurrent.SynchronousQueue;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountDao.impl.AccountDao;
import com.bbb.factory.IAccountService.IAccountService;

public class AccountService4 implements IAccountService {
	
	public  AccountService4(String name){
		System.out.println("AccountService4 创建了");
	}

	public void saveAccount() {
		
		System.out.println("AccountService4.saveAccount()");
	}

}

<?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的三种方式 -->
    <!-- 第一种方式:使用默认构造函数创建。
            在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
            采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。

    -->
    
    <bean id="accountService" class="com.bbb.factory.IAccountService.impl.AccountService4"></bean>
    
</beans>
package com.bbb.factory.client;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountService.IAccountService;

public class Client6 {

	public static void main(String[] args) {
		// 1.获取核心容器对象
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean2.xml");
		// 2.根据id获取Bean对象
		IAccountService as = (IAccountService) ac.getBean("accountService");
        as.saveAccount();
	}

}

运行结果:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accountService' defined in class path resource [bean2.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.bbb.factory.IAccountService.impl.AccountService4]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.bbb.factory.IAccountService.impl.AccountService4.<init>()
   
因为com.bbb.factory.IAccountService.impl.AccountService4中没有默认构造函数。

更改后:

package com.bbb.factory.IAccountService.impl;

import java.util.concurrent.SynchronousQueue;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountDao.impl.AccountDao;
import com.bbb.factory.IAccountService.IAccountService;

public class AccountService4 implements IAccountService {
	
	public  AccountService4(){
		System.out.println("AccountService4 创建了");
	}

	public void saveAccount() {
		
		System.out.println("AccountService4.saveAccount()");
	}

}

运行结果:

信息: Loading XML bean definitions from class path resource [bean2.xml]
AccountService4 创建了
AccountService4.saveAccount()
使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
package com.ccc.factory.BeanFactory;

import com.bbb.factory.IAccountService.IAccountService;
import com.bbb.factory.IAccountService.impl.AccountService4;

/**
 * 模拟一个工厂类(该类可能是存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数)
 */
public class InstanceFactory {

    public IAccountService getAccountService(){
        return new AccountService4();
    }
}

package com.ccc.factory.BeanFactory;

import com.bbb.factory.IAccountService.IAccountService;
import com.bbb.factory.IAccountService.impl.AccountService4;

/**
 * 模拟一个工厂类(该类可能是存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数)
 */
public class StaticFactory {

    public static IAccountService getAccountService(){

        return new AccountService4();
    }
}

<?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的三种方式 -->
	<!-- 第一种方式:使用默认构造函数创建。 在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。 
		采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。 <bean id="accountService" class="com.bbb.factory.IAccountService.impl.AccountService4"></bean> -->

	<!-- 第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器) -->
	<bean id="instanceFactory" class="com.ccc.factory.BeanFactory.InstanceFactory"></bean>
	<bean id="accountService" factory-bean="instanceFactory"
		factory-method="getAccountService"></bean>



</beans>
package com.bbb.factory.client;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountService.IAccountService;

public class Client7 {

	public static void main(String[] args) {
		// 1.获取核心容器对象
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean2.xml");
		// 2.根据id获取Bean对象
		IAccountService as = (IAccountService) ac.getBean("accountService");
        as.saveAccount();
	}

}

运行结果:

信息: Loading XML bean definitions from class path resource [bean2.xml]
AccountService4 创建了
AccountService4.saveAccount()
使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
package com.ccc.factory.BeanFactory;

import com.bbb.factory.IAccountService.IAccountService;
import com.bbb.factory.IAccountService.impl.AccountService4;

/**
 * 模拟一个工厂类(该类可能是存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数)
 */
public class StaticFactory {

    public static IAccountService getAccountService(){

        return new AccountService4();
    }
}

<?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的三种方式 -->
	<!-- 第一种方式:使用默认构造函数创建。 在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。 
		采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。 <bean id="accountService" class="com.bbb.factory.IAccountService.impl.AccountService4"></bean> -->

	<!-- 第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
	<bean id="instanceFactory" class="com.ccc.factory.BeanFactory.InstanceFactory"></bean>
	<bean id="accountService" factory-bean="instanceFactory"
		factory-method="getAccountService"></bean>
	 -->
	

<!-- 第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
    
    -->
	<bean id="accountService" class="com.ccc.factory.BeanFactory.StaticFactory" factory-method="getAccountService"></bean>
</beans>
信息: Loading XML bean definitions from class path resource [bean2.xml]
AccountService4 创建了
AccountService4.saveAccount()
singleton单例对象的销毁
package com.bbb.factory.IAccountService.impl;

import java.util.concurrent.SynchronousQueue;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountDao.impl.AccountDao;
import com.bbb.factory.IAccountService.IAccountService;

public class AccountService5 implements IAccountService {
	
	public  AccountService5(){
		System.out.println("AccountService4 创建了");
	}

	public void saveAccount() {
		
		System.out.println("AccountService4.saveAccount()");
	}
	
	public void  init(){
        System.out.println("对象初始化了。。。");
    }
    public void  destroy(){
        System.out.println("对象销毁了。。。");
    }

}

<?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来管理-->
    <!--spring对bean的管理细节
        1.创建bean的三种方式
        2.bean对象的作用范围
        3.bean对象的生命周期
    -->
    
	<!--创建Bean的三种方式 -->
	<!-- 第一种方式:使用默认构造函数创建。 在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。 
		采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。 
		<bean id="accountService" class="com.bbb.factory.IAccountService.impl.AccountService4"></bean> -->

	<!-- 第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
	<bean id="instanceFactory" class="com.ccc.factory.BeanFactory.InstanceFactory"></bean>
	<bean id="accountService" factory-bean="instanceFactory"
		factory-method="getAccountService"></bean>
	 -->
	

<!-- 第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
    <bean id="accountService" class="com.ccc.factory.BeanFactory.StaticFactory" factory-method="getAccountService"></bean>
    -->
	
	
	    <!-- bean的作用范围调整
        bean标签的scope属性:
            作用:用于指定bean的作用范围
            取值: 常用的就是单例的和多例的
                singleton:单例的(默认值)
                prototype:多例的
                request:作用于web应用的请求范围
                session:作用于web应用的会话范围
                global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session
    -->
    <!-- bean对象的生命周期
            单例对象
                出生:当容器创建时对象出生
                活着:只要容器还在,对象一直活着
                死亡:容器销毁,对象消亡
                总结:单例对象的生命周期和容器相同
            多例对象
                出生:当我们使用对象时spring框架为我们创建
                活着:对象只要是在使用过程中就一直活着。
                死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收
     -->
    <bean id="accountService" class="com.bbb.factory.IAccountService.impl.AccountService5" scope="singleton" init-method="init" destroy-method="destroy"></bean>
</beans>
package com.bbb.factory.client;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountService.IAccountService;

public class Client8 {

	public static void main(String[] args) {
		// 1.获取核心容器对象
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean2.xml");
		// 2.根据id获取Bean对象
		IAccountService as1 = (IAccountService) ac.getBean("accountService");
		IAccountService as2 = (IAccountService) ac.getBean("accountService");
		System.out.println(as1==as2);
		
		//手动关闭容器
        ac.close();

	}

}

运行结果:

信息: Loading XML bean definitions from class path resource [bean2.xml]
AccountService4 创建了
对象初始化了。。。
true
十一月 02, 2020 6:22:55 下午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@5a2e4553: startup date [Mon Nov 02 18:22:55 CST 2020]; root of context hierarchy
对象销毁了。。。
多例对象的销毁
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"
          scope="prototype" init-method="init" destroy-method="destroy"></bean>
    
单例对象
    出生:当容器创建时对象出生
    活着:只要容器还在,对象一直活着
    死亡:容器销毁,对象消亡
    总结:单例对象的生命周期和容器相同
多例对象
    出生:当我们使用对象时spring框架为我们创建
    活着:对象只要是在使用过程中就一直活着。
    死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收

7 spring中bean的细节之作用范围


8 spring中bean的细节之生命周期


9 spring的依赖注入


10 构造函数注入

构造函数注入:
	使用的标签:constructor-arg
	标签出现的位置:bean标签的内部
	标签中的属性
	type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
	index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
	name:用于指定给构造函数中指定名称的参数赋值  常用的
	=============以上三个用于指定给构造函数中哪个参数赋值===========
	value:用于提供基本类型和String类型的数据
	ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象

优势:
	在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
弊端:
	改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
package com.ddd.service.impl;

import java.util.Date;

import com.ddd.service.IAccountService;

public class AccountService implements IAccountService {

	//如果是经常变化的数据,并不适用于注入的方式
    private String name;
    private Integer age;
    private Date birthday;

    public AccountService(String name,Integer age,Date birthday){
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public void  saveAccount(){
        System.out.println("service中的saveAccount方法执行了。。。"+name+","+age+","+birthday);
    }

}

<?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 id="accountService" class="com.ddd.service.impl.AccountService">
		<constructor-arg name="name" value="泰斯特"></constructor-arg>
		<constructor-arg name="age" value="18"></constructor-arg>
		<constructor-arg name="birthday" ref="now"></constructor-arg>
	</bean>
	
	<!-- 配置一个日期对象 -->
    <bean id="now" class="java.util.Date"></bean>
</beans>
package com.ddd.client;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ddd.service.IAccountService;

public class Client {

    public static void main(String[] args) {
        //1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean3.xml");
        //2.根据id获取Bean对象
        IAccountService as  = (IAccountService)ac.getBean("accountService");
        as.saveAccount();


    }
}

运行结果:

信息: Loading XML bean definitions from class path resource [bean3.xml]
service中的saveAccount方法执行了。。。泰斯特,18,Mon Nov 02 18:46:04 CST 2020

11 set方法注入

set方法注入                更常用的方式
	涉及的标签:property
	出现的位置:bean标签的内部
	标签的属性
		name:用于指定注入时所调用的set方法名称
		value:用于提供基本类型和String类型的数据
		ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
	优势:
		创建对象时没有明确的限制,可以直接使用默认构造函数
	弊端:
		如果有某个成员必须有值,则获取对象是有可能set方法没有执行。
package com.ddd.service.impl;

import java.util.Date;

import com.ddd.service.IAccountService;

public class AccountService2 implements IAccountService {

	//如果是经常变化的数据,并不适用于注入的方式
    private String name;
    private Integer age;
    private Date birthday;

	public void setName(String name) {
		this.name = name;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public void  saveAccount(){
        System.out.println("service中的saveAccount方法执行了。。。"+name+","+age+","+birthday);
    }

}

<?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 id="accountService" class="com.ddd.service.impl.AccountService">
		<constructor-arg name="name" value="泰斯特"></constructor-arg>
		<constructor-arg name="age" value="18"></constructor-arg>
		<constructor-arg name="birthday" ref="now"></constructor-arg>
	</bean>
	
	<!-- 配置一个日期对象 -->
    <bean id="now" class="java.util.Date"></bean>
    
    <bean id="accountService2" class="com.ddd.service.impl.AccountService2">
		<property name="name" value="TEST" ></property>
		<property name="age" value="21"></property>
		<property name="birthday" ref="now"></property>
	</bean>
</beans>
package com.ddd.client;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ddd.service.IAccountService;

public class Client2 {

    public static void main(String[] args) {
        //1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean3.xml");
        //2.根据id获取Bean对象
        IAccountService as  = (IAccountService)ac.getBean("accountService2");
        as.saveAccount();


    }
}

运行结果:

信息: Loading XML bean definitions from class path resource [bean3.xml]
service中的saveAccount方法执行了。。。TEST,21,Mon Nov 02 18:54:56 CST 2020

注意:

<property name="name" value="TEST" ></property>中的name=""属性取决于class AccountService2中的set方法:去掉set后面小写。

12 注入集合数据


import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import com.ddd.service.IAccountService;

public class AccountServiceImpl3 implements IAccountService{

	private String[] myStrs;
    private List<String> myList;
    private Set<String> mySet;
    private Map<String,String> myMap;
    private Properties myProps;

    public void setMyStrs(String[] myStrs) {
        this.myStrs = myStrs;
    }

    public void setMyList(List<String> myList) {
        this.myList = myList;
    }

    public void setMySet(Set<String> mySet) {
        this.mySet = mySet;
    }

    public void setMyMap(Map<String, String> myMap) {
        this.myMap = myMap;
    }

    public void setMyProps(Properties myProps) {
        this.myProps = myProps;
    }

    public void  saveAccount(){
        System.out.println(Arrays.toString(myStrs));
        System.out.println(myList);
        System.out.println(mySet);
        System.out.println(myMap);
        System.out.println(myProps);
    }

}

<?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 id="accountService" class="com.ddd.service.impl.AccountService">
		<constructor-arg name="name" value="泰斯特"></constructor-arg>
		<constructor-arg name="age" value="18"></constructor-arg>
		<constructor-arg name="birthday" ref="now"></constructor-arg>
	</bean>

	<!-- 配置一个日期对象 -->
	<bean id="now" class="java.util.Date"></bean>

	<bean id="accountService2" class="com.ddd.service.impl.AccountService2">
		<property name="name" value="TEST"></property>
		<property name="age" value="21"></property>
		<property name="birthday" ref="now"></property>
	</bean>
	
	<bean id="accountService3" class="com.ddd.service.impl.AccountServiceImpl3">
	<property name="myStrs">
		<set>
			<value>AAA</value>
			<value>BBB</value>
			<value>CCC</value>
		</set>
	</property>

	<property name="myList">
		<list>
			<value>AAA</value>
			<value>BBB</value>
			<value>CCC</value>
		</list>
	</property>

	<property name="mySet">
		<list>
			<value>AAA</value>
			<value>BBB</value>
			<value>CCC</value>
		</list>
	</property>

	<property name="myMap">
		<map>
			<entry key="testA" value="aaa"></entry>
			<entry key="testB">
				<value>BBB</value>
			</entry>
		</map>	

	</property>

	<property name="myProps">
		<props>
			<prop key="testC">ccc</prop>
			<prop key="testD">ddd</prop>
		</props>
	</property>
</bean>
	
	
</beans>
package com.ddd.client;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ddd.service.IAccountService;

public class Client3 {

    public static void main(String[] args) {
        //1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean3.xml");
        //2.根据id获取Bean对象
        IAccountService as  = (IAccountService)ac.getBean("accountService3");
        as.saveAccount();


    }
}

运行结果:

[AAA, BBB, CCC]
[AAA, BBB, CCC]
[AAA, BBB, CCC]
{testA=aaa, testB=BBB}
{testD=ddd, testC=ccc}
复杂类型的注入/集合类型的注入
	用于给List结构集合注入的标签:
		list array set
	用于个Map结构集合注入的标签:
		map  props
	结构相同,标签可以互换

13 课程知识梳理

源码:\hello

===================================================

04.Spring的常用注解


1 今日课程内容介绍


2 常用IOC注解按照作用分类

* 用于创建对象的
 *      他们的作用就和在XML配置文件中编写一个<bean>标签实现的功能是一样的
 *      Component:
 *          作用:用于把当前类对象存入spring容器中
 *          属性:
 *              value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。
 *      Controller:一般用在表现层
 *      Service:一般用在业务层
 *      Repository:一般用在持久层
 *      以上三个注解他们的作用和属性与Component是一模一样。
 *      他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰
 *
 *
 * 用于注入数据的
 *      他们的作用就和在xml配置文件中的bean标签中写一个<property>标签的作用是一样的
 *      Autowired:
 *          作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
 *                如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
 *                如果Ioc容器中有多个类型匹配时:
 *          出现位置:
 *              可以是变量上,也可以是方法上
 *          细节:
 *              在使用注解注入时,set方法就不是必须的了。
 *      Qualifier:
 *          作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以(稍后我们讲)
 *          属性:
 *              value:用于指定注入bean的id。
 *      Resource
 *          作用:直接按照bean的id注入。它可以独立使用
 *          属性:
 *              name:用于指定bean的id。
 *      以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
 *      另外,集合类型的注入只能通过XML来实现。
 *
 *      Value
 *          作用:用于注入基本类型和String类型的数据
 *          属性:
 *              value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
 *                      SpEL的写法:${表达式}
 *
 * 用于改变作用范围的
 *      他们的作用就和在bean标签中使用scope属性实现的功能是一样的
 *      Scope
 *          作用:用于指定bean的作用范围
 *          属性:
 *              value:指定范围的取值。常用取值:singleton prototype
 *
 * 和生命周期相关 了解
 *      他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的
 *      PreDestroy
 *          作用:用于指定销毁方法
 *      PostConstruct
 *          作用:用于指定初始化方法

3 用于创建的Component注解

<?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">

    <!--告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是一个名称为
    context名称空间和约束中-->
    <context:component-scan base-package="com.bbb.factory"></context:component-scan>
</beans>
package com.bbb.factory.IAccountService.impl;

import org.springframework.stereotype.Component;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountDao.impl.AccountDao;
import com.bbb.factory.IAccountService.IAccountService;

/**
 *      Component:
 *          作用:用于把当前类对象存入spring容器中
 *          属性:
 *              value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。
 */
@Component("accountService")
public class AccountService implements IAccountService {
	
	private IAccountDao accountDao;
	
	public AccountService() {
		System.out.println("AccountService()创建了");
		
	}

	public void saveAccount() {
		
		accountDao.saveAccount();
	}

}

package com.bbb.factory.client;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountService.IAccountService;


public class Client {

	public static void main(String[] args) {
		//1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取Bean对象
        IAccountService as  = (IAccountService)ac.getBean("accountService");

        System.out.println(as);
        
	}

}

信息: Loading XML bean definitions from class path resource [bean.xml]
AccountService()创建了
com.bbb.factory.IAccountService.impl.AccountService@68ceda24

4 由Component衍生的注解

package com.bbb.factory.IAccountDao.impl;

import org.springframework.stereotype.Repository;

import com.bbb.factory.IAccountDao.IAccountDao;

@Repository("accountDao")
public class AccountDao implements IAccountDao{

	public void saveAccount() {
		System.out.println("保存了账户");
	}

}

package com.bbb.factory.client;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountService.IAccountService;


public class Client {

	public static void main(String[] args) {
		//1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取Bean对象
        IAccountService as  = (IAccountService)ac.getBean("accountService");
        IAccountDao ad = (IAccountDao)ac.getBean("accountDao");

        System.out.println(as);
        System.out.println(ad);
        
	}

}

信息: Loading XML bean definitions from class path resource [bean.xml]
AccountService()创建了
com.bbb.factory.IAccountService.impl.AccountService@5a4041cc
com.bbb.factory.IAccountDao.impl.AccountDao@15b3e5b

5 自动按照类型注入

自动注入原理.png

package com.bbb.factory.IAccountService.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountDao.impl.AccountDao;
import com.bbb.factory.IAccountService.IAccountService;

/**
 *      Component:
 *          作用:用于把当前类对象存入spring容器中
 *          属性:
 *              value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。
 */
@Service("accountService")
public class AccountService implements IAccountService {
	
	//作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
	@Autowired
	private IAccountDao accountDao;
	
	public AccountService() {
		System.out.println("AccountService()创建了");
		
	}

	public void saveAccount() {
		
		accountDao.saveAccount();
	}

}

如果Ioc容器中有多个类型匹配时.png

![](.assets/ 如果Ioc容器中有多个类型匹配时.png)

package com.bbb.factory.IAccountDao.impl;

import org.springframework.stereotype.Repository;

import com.bbb.factory.IAccountDao.IAccountDao;

@Repository("accountDao1")
public class AccountDao implements IAccountDao{

	public void saveAccount() {
		System.out.println("保存了账户accountDao()");
	}

}
package com.bbb.factory.IAccountDao.impl;

import org.springframework.stereotype.Repository;

import com.bbb.factory.IAccountDao.IAccountDao;

@Repository("accountDao2")
public class AccountDao2 implements IAccountDao{

	public void saveAccount() {
		System.out.println("保存了账户accountDao2()");
	}

}
package com.bbb.factory.IAccountService.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.bbb.factory.IAccountDao.IAccountDao;
import com.bbb.factory.IAccountDao.impl.AccountDao;
import com.bbb.factory.IAccountService.IAccountService;

/**
 *      Component:
 *          作用:用于把当前类对象存入spring容器中
 *          属性:
 *              value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。
 */
@Service("accountService")
public class AccountService implements IAccountService {
	
	//作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
	@Autowired
	private IAccountDao accountDao;
	
	public AccountService() {
		System.out.println("AccountService()创建了");
		
	}

	public void saveAccount() {
		
		accountDao.saveAccount();
	}

}

@Autowired
private IAccountDao accountDao

如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
如果Ioc容器中有多个类型匹配时:
1.容器中bean对象类型和要注入的变量类型IAccountDao匹配
2.要注入的变量名称accountDao匹配容器中accountDao1和accountDao2

6 用于注入数据的注解

*      Qualifier:
 *          作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以(稍后我们讲)
 *          属性:
 *              value:用于指定注入bean的id。
 
*      Resource
 *          作用:直接按照bean的id注入。它可以独立使用
 *          属性:
 *              name:用于指定bean的id。
 *      Value
 *          作用:用于注入基本类型和String类型的数据
 *          属性:
 *              value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
 *                      SpEL的写法:${表达式}

7 改变作用范围以及和生命周期相关的注解

package com.itheima.service.impl;

import com.itheima.dao.IAccountDao;
import com.itheima.service.IAccountService;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

/**
 * 账户的业务层实现类
 *
 * 曾经XML的配置:
 *  <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"
 *        scope=""  init-method="" destroy-method="">
 *      <property name=""  value="" | ref=""></property>
 *  </bean>
 *
 * 用于创建对象的
 *      他们的作用就和在XML配置文件中编写一个<bean>标签实现的功能是一样的
 *      Component:
 *          作用:用于把当前类对象存入spring容器中
 *          属性:
 *              value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。
 *      Controller:一般用在表现层
 *      Service:一般用在业务层
 *      Repository:一般用在持久层
 *      以上三个注解他们的作用和属性与Component是一模一样。
 *      他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰
 *
 *
 * 用于注入数据的
 *      他们的作用就和在xml配置文件中的bean标签中写一个<property>标签的作用是一样的
 *      Autowired:
 *          作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
 *                如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
 *                如果Ioc容器中有多个类型匹配时:
 *          出现位置:
 *              可以是变量上,也可以是方法上
 *          细节:
 *              在使用注解注入时,set方法就不是必须的了。
 *      Qualifier:
 *          作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以(稍后我们讲)
 *          属性:
 *              value:用于指定注入bean的id。
 *      Resource
 *          作用:直接按照bean的id注入。它可以独立使用
 *          属性:
 *              name:用于指定bean的id。
 *      以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
 *      另外,集合类型的注入只能通过XML来实现。
 *
 *      Value
 *          作用:用于注入基本类型和String类型的数据
 *          属性:
 *              value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
 *                      SpEL的写法:${表达式}
 *
 * 用于改变作用范围的
 *      他们的作用就和在bean标签中使用scope属性实现的功能是一样的
 *      Scope
 *          作用:用于指定bean的作用范围
 *          属性:
 *              value:指定范围的取值。常用取值:singleton prototype
 *
 * 和生命周期相关 了解
 *      他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的
 *      PreDestroy
 *          作用:用于指定销毁方法
 *      PostConstruct
 *          作用:用于指定初始化方法
 */
@Service("accountService")
//@Scope("prototype")
public class AccountServiceImpl implements IAccountService {

//    @Autowired
//    @Qualifier("accountDao1")
    @Resource(name = "accountDao2")
    private IAccountDao accountDao = null;

    @PostConstruct
    public void  init(){
        System.out.println("初始化方法执行了");
    }

    @PreDestroy
    public void  destroy(){
        System.out.println("销毁方法执行了");
    }

    public void  saveAccount(){
        accountDao.saveAccount();
    }
}
源码:\helloNano

===================================================

05.基于XML的IOC的案例1


1 测试基于XML的IOC案例

源码:day02_eesy_02account_xmlioc
范例:
package com.itheima.test;

import com.itheima.domain.Account;
import com.itheima.service.IAccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

/**
 * 使用Junit单元测试:测试我们的配置
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTest {

    @Autowired
    private  IAccountService as;

    @Test
    public void testFindAll() {
        //3.执行方法
        List<Account> accounts = as.findAllAccount();
        for(Account account : accounts){
            System.out.println(account);
        }
    }

    @Test
    public void testFindOne() {
        //3.执行方法
        Account account = as.findAccountById(1);
        System.out.println(account);
    }

    @Test
    public void testSave() {
        Account account = new Account();
        account.setName("test");
        account.setMoney(12345f);
        //3.执行方法
        as.saveAccount(account);

    }

    @Test
    public void testUpdate() {
        //3.执行方法
        Account account = as.findAccountById(4);
        account.setMoney(23456f);
        as.updateAccount(account);
    }

    @Test
    public void testDelete() {
        //3.执行方法
        as.deleteAccount(4);
    }
}


2 基于XML的IOC的案例-编写spring的Ioc配置


3 基于XML的IOC的案例-案例准备


4 注解IOC案例-把自己编写的类使用注解配置

===================================================

06.Spring的新注解


1 spring的新注解-Configuration和ComponentScan


2 spring的新注解-Bean


3 AnnotationConfigApplicationContext的使用


4 spring的新注解-Import


5 spring的新注解-PropertySource


6 Qualifier注解的另一种用法

package config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;

/**
 * 该类是一个配置类,它的作用和bean.xml是一样的
 * spring中的新注解
 * Configuration
 *     作用:指定当前类是一个配置类
 *     细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。
 * ComponentScan
 *      作用:用于通过注解指定spring在创建容器时要扫描的包
 *      属性:
 *          value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。
 *                 我们使用此注解就等同于在xml中配置了:
 *                      <context:component-scan base-package="com.itheima"></context:component-scan>
 *  Bean
 *      作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
 *      属性:
 *          name:用于指定bean的id。当不写时,默认值是当前方法的名称
 *      细节:
 *          当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。
 *          查找的方式和Autowired注解的作用是一样的
 *  Import
 *      作用:用于导入其他的配置类
 *      属性:
 *          value:用于指定其他配置类的字节码。
 *                  当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类
 *  PropertySource
 *      作用:用于指定properties文件的位置
 *      属性:
 *          value:指定文件的名称和路径。
 *                  关键字:classpath,表示类路径下
 */
//@Configuration
@ComponentScan("com.itheima")
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {


}

package config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
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.Scope;

import javax.sql.DataSource;

/**
 * 和spring连接数据库相关的配置类
 */
public class JdbcConfig {

    @Value("${jdbc.driver}")
    private String driver;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    /**
     * 用于创建一个QueryRunner对象
     * @param dataSource
     * @return
     */
    @Bean(name="runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(@Qualifier("ds2") DataSource dataSource){
        return new QueryRunner(dataSource);
    }

    /**
     * 创建数据源对象
     * @return
     */
    @Bean(name="ds2")
    public DataSource createDataSource(){
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    @Bean(name="ds1")
    public DataSource createDataSource1(){
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl("jdbc:mysql://localhost:3306/eesy02");
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

源码:\app

7 spring整合junit问题分析


8 spring整合junit完成

===================================================

07.银行转账案例


1 今日课程内容介绍


2 案例中添加转账方法并演示事务问题


3 分析事务的问题并编写ConnectionUtils


4 编写事务管理工具类并分析连接和线程解绑


5 编写业务层和持久层事务控制代码并配置spring的ioc


6 测试转账并分析案例中的问题


7 代理的分析


8 基于接口的动态代理回顾

基于接口的动态代理
/**
 * 一个生产者
 */
public class Producer implements IProducer{

    /**
     * 销售
     * @param money
     */
    public void saleProduct(float money){
        System.out.println("销售产品,并拿到钱:"+money);
    }

    /**
     * 售后
     * @param money
     */
    public void afterService(float money){
        System.out.println("提供售后服务,并拿到钱:"+money);
    }
}
/**
 * 对生产厂家要求的接口
 */
public interface IProducer {

    /**
     * 销售
     * @param money
     */
    public void saleProduct(float money);

    /**
     * 售后
     * @param money
     */
    public void afterService(float money);
}


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 模拟一个消费者
 */
public class Client {

    public static void main(String[] args) {
        final Producer producer = new Producer();

        /**
         * 动态代理:
         *  特点:字节码随用随创建,随用随加载
         *  作用:不修改源码的基础上对方法增强
         *  分类:
         *      基于接口的动态代理
         *      基于子类的动态代理
         *  基于接口的动态代理:
         *      涉及的类:Proxy
         *      提供者:JDK官方
         *  如何创建代理对象:
         *      使用Proxy类中的newProxyInstance方法
         *  创建代理对象的要求:
         *      被代理类最少实现一个接口,如果没有则不能使用
         *  newProxyInstance方法的参数:
         *      ClassLoader:类加载器
         *          它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。
         *      Class[]:字节码数组
         *          它是用于让代理对象和被代理对象有相同方法。固定写法。
         *      InvocationHandler:用于提供增强的代码
         *          它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
         *          此接口的实现类都是谁用谁写。
         */
       IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                producer.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 作用:执行被代理对象的任何接口方法都会经过该方法
                     * 方法参数的含义
                     * @param proxy   代理对象的引用
                     * @param method  当前执行的方法
                     * @param args    当前执行方法所需的参数
                     * @return        和被代理对象方法有相同的返回值
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //提供增强的代码
                        Object returnValue = null;

                        //1.获取方法执行的参数
                        Float money = (Float)args[0];
                        //2.判断当前方法是不是销售
                        if("saleProduct".equals(method.getName())) {
                            returnValue = method.invoke(producer, money*0.8f);
                        }
                        return returnValue;
                    }
                });
        proxyProducer.saleProduct(10000f);
    }
}
源码:day03_eesy_02proxy

9 基于子类的动态代理

/**
 * 一个生产者
 */
public class Producer {

    /**
     * 销售
     * @param money
     */
    public void saleProduct(float money){
        System.out.println("销售产品,并拿到钱:"+money);
    }

    /**
     * 售后
     * @param money
     */
    public void afterService(float money){
        System.out.println("提供售后服务,并拿到钱:"+money);
    }
}

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 模拟一个消费者
 */
public class Client {

    public static void main(String[] args) {
        final Producer producer = new Producer();

        /**
         * 动态代理:
         *  特点:字节码随用随创建,随用随加载
         *  作用:不修改源码的基础上对方法增强
         *  分类:
         *      基于接口的动态代理
         *      基于子类的动态代理
         *  基于子类的动态代理:
         *      涉及的类:Enhancer
         *      提供者:第三方cglib库
         *  如何创建代理对象:
         *      使用Enhancer类中的create方法
         *  创建代理对象的要求:
         *      被代理类不能是最终类
         *  create方法的参数:
         *      Class:字节码
         *          它是用于指定被代理对象的字节码。
         *
         *      Callback:用于提供增强的代码
         *          它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
         *          此接口的实现类都是谁用谁写。
         *          我们一般写的都是该接口的子接口实现类:MethodInterceptor
         */
        Producer cglibProducer = (Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() {
            /**
             * 执行北地阿里对象的任何方法都会经过该方法
             * @param proxy
             * @param method
             * @param args
             *    以上三个参数和基于接口的动态代理中invoke方法的参数是一样的
             * @param methodProxy :当前执行方法的代理对象
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //提供增强的代码
                Object returnValue = null;

                //1.获取方法执行的参数
                Float money = (Float)args[0];
                //2.判断当前方法是不是销售
                if("saleProduct".equals(method.getName())) {
                    returnValue = method.invoke(producer, money*0.8f);
                }
                return returnValue;
            }
        });
        cglibProducer.saleProduct(12000f);
    }
}


10 使用动态代理实现事务控制

源码:day03_eesy_01account

===================================================

08.面向切面编程 AOP


1 AOP的概念


2 spring中的aop术语和细节


3 spring基于XML的AOP-编写必要的代码


4 spring基于XML的AOP-配置步骤

<?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>day03_eesy_03springAOP</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>
    </dependencies>
</project>
/**
 * 账户的业务层实现类
 */
public class AccountServiceImpl implements IAccountService{

    @Override
    public void saveAccount() {
        System.out.println("执行了保存");
    }

    @Override
    public void updateAccount(int i) {
        System.out.println("执行了更新"+i);

    }

    @Override
    public int deleteAccount() {
        System.out.println("执行了删除");
        return 0;
    }
}

/**
 * 用于记录日志的工具类,它里面提供了公共的代码
 */
public class Logger {

    /**
     * 用于打印日志:计划让其在切入点方法执行之前执行(切入点方法就是业务层方法)
     */
    public  void printLog(){
        System.out.println("Logger类中的pringLog方法开始记录日志了。。。");
    }
}
<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 配置srping的Ioc,把service对象配置进来-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>

    <!--spring中基于XML的AOP配置步骤
        1、把通知Bean也交给spring来管理
        2、使用aop:config标签表明开始AOP的配置
        3、使用aop:aspect标签表明配置切面
                id属性:是给切面提供一个唯一标识
                ref属性:是指定通知类bean的Id。
        4、在aop:aspect标签的内部使用对应标签来配置通知的类型
               我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知
               aop:before:表示配置前置通知
                    method属性:用于指定Logger类中哪个方法是前置通知
                    pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强

            切入点表达式的写法:
                关键字:execution(表达式)
                表达式:
                    访问修饰符  返回值  包名.包名.包名...类名.方法名(参数列表)
                标准的表达式写法:
                    public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
                访问修饰符可以省略
                    void com.itheima.service.impl.AccountServiceImpl.saveAccount()
                返回值可以使用通配符,表示任意返回值
                    * com.itheima.service.impl.AccountServiceImpl.saveAccount()
                包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
                    * *.*.*.*.AccountServiceImpl.saveAccount())
                包名可以使用..表示当前包及其子包
                    * *..AccountServiceImpl.saveAccount()
                类名和方法名都可以使用*来实现通配
                    * *..*.*()
                参数列表:
                    可以直接写数据类型:
                        基本类型直接写名称           int
                        引用类型写包名.类名的方式   java.lang.String
                    可以使用通配符表示任意类型,但是必须有参数
                    可以使用..表示有无参数均可,有参数可以是任意类型
                全通配写法:
                    * *..*.*(..)

                实际开发中切入点表达式的通常写法:
                    切到业务层实现类下的所有方法
                        * com.itheima.service.impl.*.*(..)
    -->

    <!-- 配置Logger类 -->
    <bean id="logger" class="com.itheima.utils.Logger"></bean>

    <!--配置AOP-->
    <aop:config>
        <!--配置切面 -->
        <aop:aspect id="logAdvice" ref="logger">
            <!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
            <aop:before method="printLog" pointcut="execution(* com.itheima.service.impl.*.*(..))"></aop:before>
        </aop:aspect>
    </aop:config>

</beans>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 测试AOP的配置
 */
public class AOPTest {

    public static void main(String[] args) {
        //1.获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取对象
        IAccountService as = (IAccountService)ac.getBean("accountService");
        //3.执行方法
        as.saveAccount();
        as.updateAccount(1);
        as.deleteAccount();
    }
}

5 切入点表达式的写法


6 四种常用通知类型

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 配置srping的Ioc,把service对象配置进来-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>


    <!-- 配置Logger类 -->
    <bean id="logger" class="com.itheima.utils.Logger"></bean>

    <!--配置AOP-->
    <aop:config>
        <!-- 配置切入点表达式 id属性用于指定表达式的唯一标识。expression属性用于指定表达式内容
              此标签写在aop:aspect标签内部只能当前切面使用。
              它还可以写在aop:aspect外面,此时就变成了所有切面可用
          -->
        <aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>
        <!--配置切面 -->
        <aop:aspect id="logAdvice" ref="logger">
            <!-- 配置前置通知:在切入点方法执行之前执行
            <aop:before method="beforePrintLog" pointcut-ref="pt1" ></aop:before>-->

            <!-- 配置后置通知:在切入点方法正常执行之后值。它和异常通知永远只能执行一个
            <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>-->

            <!-- 配置异常通知:在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个
            <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>-->

            <!-- 配置最终通知:无论切入点方法是否正常执行它都会在其后面执行
            <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>-->

            <!-- 配置环绕通知 详细的注释请看Logger类中-->
            <aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>
        </aop:aspect>
    </aop:config>

</beans>
四种常用通知类型.png


7 通用化切入点表达式


8 spring中的环绕通知


9 spring基于注解的AOP配置


10 总结和作业安排

===================================================

09.JdbcTemplate的基本使用


1 今日课程内容介绍


2 JdbcTemplate的概述和入门


3 JdbcTemplate在Dao中的使用


4 JdbcTemplate的CRUD操作


5 JdbcTemplate在spring的ioc中使用


6 JdbcDaoSupport的使用以及Dao的两种编写方式

===================================================

10.Spring中事务控制


1 基于XML的AOP实现事务控制


2 作业-基于注解的AOP实现事务控制及问题分析_上


3 作业-基于注解的AOP实现事务控制及问题分析_下


4 spring中事务控制的一组API


5 spring事务控制的代码准备


6 spring基于XML的声明式事务控制-配置步骤


7 spring基于注解的声明式事务控制


8 spring基于纯注解的声明式事务控制


9 spring编程式事务控制1-了解


10spring编程式事务控制2-了解


11 spring5新特性的介绍

Copyright © 2024 锦喵卫指挥使
Powered by .NET 8.0 on Kubernetes