2、spring的第二种注入方法:基于构造方法完成对属性值的注入

    1. <bean id="user" class="com.jy.beans.User">
    2. <!--通过构造注入数据-->
    3. <constructor-arg name="name" value="dnflaksd"></constructor-arg>
    4. <constructor-arg name="date" ref="date"></constructor-arg>
    5. </bean>
    6. <bean id="date" class="java.util.Date"></bean>

    七、关于组件的生命周期
    a.组件的作用范围是单例:组件会随着容器的销毁而销毁。
    b.组件的作用范围是多例:容器销毁时,组件不会销毁,会由垃圾回收机制回收。

    八、模拟spring底层基于工厂模式解耦
    首先程序会读取配置文件,获取文件中的全类名数据,根据反射创建对象(单例),保存在容器中,后面如果有用到实例的地方,我们从容器中获取。
    beans.properties

    1. caseServlet = com.jy.factory.servlet.CaseServlet
    2. caseService = com.jy.factory.service.CaseServiceImpl
    3. caseDao = com.jy.factory.dao.CaseDaoImpl

    BeanFactory:

    1. public class BeanFactory {
    2. /**
    3. * 模拟一个容器
    4. */
    5. private static Map beansMap;
    6. private static Properties properties;
    7. /**
    8. * 在静态代码块中创建容器对象,是为了保证存入容器中的实例是单例的,所有的存放实例的步骤,
    9. * 也要在类加载的时候完成
    10. */
    11. static {
    12. //实例化容器
    13. beansMap = new HashMap();
    14. //实例化properties集合
    15. properties = new Properties();
    16. FileReader fileReader = null;
    17. //读取配置文件
    18. try {
    19. fileReader = new FileReader("src/beans.properties");
    20. //读取数据到集合
    21. properties.load(fileReader);
    22. //获取properties中所有的key
    23. Enumeration keys = properties.keys();
    24. //遍历所有的key
    25. while (keys.hasMoreElements()){
    26. //先获取对应key的字符串
    27. String s = keys.nextElement().toString();
    28. //根据key获取value
    29. String propertyClass = properties.getProperty(s);
    30. //根据反射创建对象
    31. Object value = Class.forName(propertyClass).newInstance();
    32. //将实例存到容器里
    33. beansMap.put(s,value);
    34. }
    35. } catch (Exception e) {
    36. e.printStackTrace();
    37. } finally {
    38. try {
    39. fileReader.close();
    40. } catch (IOException e) {
    41. e.printStackTrace();
    42. }
    43. }
    44. }
    45. /**
    46. * 定义一个获取实例的方法
    47. */
    48. public static Object getBean(String beanName){
    49. //从集合中获取实例
    50. Object o = beansMap.get(beanName);
    51. return o;
    52. }
    53. }

    持久层:CaseDaoImpl

    1. public class CaseDaoImpl implements CaseDao{
    2. @Override
    3. public void getMethod() {
    4. System.out.println("持久层数据");
    5. }
    6. }

    业务层:CaseServiceImpl

    1. public class CaseServiceImpl implements CaseService{
    2. @Override
    3. public void getMethod() {
    4. CaseDao caseDao = (CaseDao)BeanFactory.getBean("caseDao");
    5. caseDao.getMethod();
    6. }
    7. }

    表现层:CaseServlet

    1. public class CaseServlet {
    2. public void getMethod(){
    3. /**
    4. * 从工厂中获取实例
    5. */
    6. CaseService caseService = (CaseService)BeanFactory.getBean("caseService");
    7. caseService.getMethod();
    8. }
    9. }

    测试:

    1. public static void main(String[] args) {
    2. //从自定义工厂对象中获取表现层实例
    3. CaseServlet caseServlet = (CaseServlet)BeanFactory.getBean("caseServlet");
    4. caseServlet.getMethod();
    5. }

    九、基于注解的IOC配置

    1、在配置文件上开启spring对注解的支持

    1. <!--
    2. 开启spring对注解的支持:其实就是一个扫描包的过程
    3. spring程序在执行的时候会解析配置文件的数据,找到对应的包结构,并扫描该包下面的子包,
    4. 然后回去检测每个类上有没有spring提供的注解,如果有,会将该类的实例装载进spring容器中
    5. -->
    6. <context:component-scan base-package="com.jy"></context:component-scan>

    2、在类上加上对应的注解
    四个注解作用一样:
    @Component:把资源让spring来管理,相当于在xml中配置一个bean
    @Controller:一般用于表现层的注解
    @Service:一般用于业务层的注解
    @Repository:一般用于持久层的注解

    1. @Component
    2. public class Student {
    3. }
    4. /**
    5. *核心容器对象获取实例时,其标识(参数)默认为首字母小写的类名
    6. */
    7. public static void main(String[] args) {
    8. ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("xml/beans2.xml");
    9. Object user = classPathXmlApplicationContext.getBean("student");
    10. System.out.println(user);
    11. }

    四个注解都可以自定义标识

    1. @Component("sss")
    2. public class Student {
    3. }
    4. /**
    5. *核心容器对象获取实例时,其标识(参数)默认为首字母小写的类名
    6. */
    7. public static void main(String[] args) {
    8. ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("xml/beans2.xml");
    9. Object user = classPathXmlApplicationContext.getBean("sss");
    10. System.out.println(user);
    11. }

    @Scope:可以改变bean的作用范围
    如:@Scope(“prototype”)

    生命周期相关:
    @PostConstruct:用于指定初始化的方法
    @PreDestroy:用于指定销毁的方法

    1. @Component
    2. @Scope("prototype")
    3. public class Student {
    4. @PostConstruct
    5. public void initMethod(){
    6. System.out.println("初始化的方法");
    7. }
    8. @PreDestroy
    9. public void destroyMethod(){
    10. System.out.println("销毁的方法");
    11. }
    12. }

    用于注入数据的注解:
    @Autowired(根据类型注入):
    注入流程:spring扫描到属性上有该注解后,会去容器中找到该属性对应的类型与之注入。
    如果spring容器中与该属性类型匹配的有多个,比如一个接口有多个实现类,实现类都采用了注解的默认值,那么究竟该注入哪个实例?
    这种情况下程序会报错!
    解决方案:
    1、给这个类起标识, 标识要和被注入属性的属性名相同。
    image.png
    image.png
    2、与Qualifier结合使用,由Qualifier来决定注入哪个实例。
    @Qualifier(不能单独使用):只能和Autowired结合使用
    @Resource(根据id注入的)
    @Value(用于注入基本数据类型和String类型):支持el表达式。不能直接注入静态属性。