2024.3.15@spring框架学习笔记

P70  IoC注解之反射注解
P70 start :
Component文件中的 内容:

package com.powernode.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解。
 */


//标注注解的注解,叫做元注解。@Target注解用来修饰@Component可与出现的位置.
//以下表示@Component注解可以出现在类上,属性上。
//@Target(value = {ElementType.TYPE,ElementType.FIELD})
//以下表示@Component注解可以出现在类上
//@Target(value = {ElementType.TYPE})
//使用某个注解的时候,如果注解的属性名是value的话,value可以省略。
//@Target({ElementType.TYPE})
//使用某个注解的时候,如果注解的属性值是数组,并且数组中只有一个元素,大括号可以省略。
@Target(ElementType.TYPE)
//@Retention(RetentionPolicy.SOURCE),表示这个注解只保留在java源文件里面
//@Retention(RetentionPolicy.CLASS),表示java源文件和class文件中都有但是不能被反射机制读取
//@Retention需要被反射的话需要写RUNTIME
//@Retention 也是一个元注解。用来标注@Component注解最终保留在class文件当中,并且可以被反射机制读取。
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {

    //定义注解的属性
    //String是属性类型
    //value是属性名
    String value();

    //其他的属性
    //属性类型是String
    //属性名是name
    //String name();

    //数组属性
    //属性类型是: String[]
    //属性名:names
    //String[] names();

    //int[] ages();
    //int age();

}

User类中的内容:

package com.powernode.bean;


import com.powernode.annotation.Component;

//@Component(属性名 = 属性值, 属性名 = 属性值,属性名 = 属性值...)
//@Component(value="userBean")
//如果属性名是value,value可以省略。
@Component("userBean")
public class User {

    //编译器报错,不能出现在这里。
    //@Component(value = "test")
    // private String name;

}

ReflectAnnotationTest1类中的内容:

package com.powernode.client;

import com.powernode.annotation.Component;

public class ReflectAnnotationTest1 {
    public static void main(String[] args) throws Exception{
        //通过反射机制怎么读取注解
        //获取类
        Class<?> aClass = Class.forName("com.powernode.bean.User");
        //判断类上面有没有这个注解
        if (aClass.isAnnotationPresent(Component.class)) {
            //获取类上的注解
            Component annotation = aClass.getAnnotation(Component.class);
            //访问注解属性
            System.out.println(annotation.value());
        }


    }
}

运行结果:
userBean

P70  END
P71 Spring IoC注解之组件扫描原理
P71 start :
'.'在正则表达式里代表任意字符
Component注解文件中的内容:

package com.powernode.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解。
 */


//标注注解的注解,叫做元注解。@Target注解用来修饰@Component可与出现的位置.
//以下表示@Component注解可以出现在类上,属性上。
//@Target(value = {ElementType.TYPE,ElementType.FIELD})
//以下表示@Component注解可以出现在类上
//@Target(value = {ElementType.TYPE})
//使用某个注解的时候,如果注解的属性名是value的话,value可以省略。
//@Target({ElementType.TYPE})
//使用某个注解的时候,如果注解的属性值是数组,并且数组中只有一个元素,大括号可以省略。
@Target(ElementType.TYPE)
//@Retention(RetentionPolicy.SOURCE),表示这个注解只保留在java源文件里面
//@Retention(RetentionPolicy.CLASS),表示java源文件和class文件中都有但是不能被反射机制读取
//@Retention需要被反射的话需要写RUNTIME
//@Retention 也是一个元注解。用来标注@Component注解最终保留在class文件当中,并且可以被反射机制读取。
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {

    //定义注解的属性
    //String是属性类型
    //value是属性名
    String value();

    //其他的属性
    //属性类型是String
    //属性名是name
    //String name();

    //数组属性
    //属性类型是: String[]
    //属性名:names
    //String[] names();

    //int[] ages();
    //int age();

}


Order类中的内容:
package com.powernode.bean;

import com.powernode.annotation.Component;

//@Component("orderBean")
public class Order {
}


User类中的内容:
package com.powernode.bean;


import com.powernode.annotation.Component;

//@Component(属性名 = 属性值, 属性名 = 属性值,属性名 = 属性值...)
//@Component(value="userBean")
//如果属性名是value,value可以省略。
//@Component("userBean")
public class User {

    //编译器报错,不能出现在这里。
    //@Component(value = "test")
    // private String name;

}


Vip类中的内容:
package com.powernode.bean;

import com.powernode.annotation.Component;

@Component("vipBean")
public class Vip {
}


ComponentScan类中的内容:
package com.powernode.client;

import com.powernode.annotation.Component;

import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class ComponentScan {
    public static void main(String[] args){
        Map<String,Object> beanMap = new HashMap<>();
        //目前只知道一个包的名字,扫描这个包下所有的类,当这个类上有@Component注解的时候,实例化该对象,然后放到Map集合中。
        String packageName = "com.powernode.bean";
        //开始写扫描程序
        //  . 这个正则表达式代表任意字符。这里的"."必须是一个普通的“.”字符。不能是正则表达式中的“.”
        //在正则表达式当中怎么表示一个普通的“.”字符呢?使用  \.  正则表达式代表一个普通的  . 字符。
        String packagePath = packageName.replaceAll("\\.", "/");
        //System.out.println(packagePath);
        // com是在类的根路径下的一个目录。
        URL url = ClassLoader.getSystemClassLoader().getResource(packagePath);
        String path = url.getPath();
        //System.out.println(path);
        //获取一个绝对路径下的所有文件
        File file = new File(path);
        File[] files = file.listFiles();
        Arrays.stream(files).forEach(f ->{

            try{
                //System.out.println(f.getName());
                //System.out.println(f.getName().split("\\.")[0]);
                String className = packageName + "." + f.getName().split("\\.")[0];
                //System.out.println(className);
                //通过反射机制解析注解
                Class<?> aClass = Class.forName(className);
                //判断类上是否有这个注解
                if (aClass.isAnnotationPresent(Component.class)) {
                    //获取注解
                    Component annotation = aClass.getAnnotation(Component.class);
                    String id = annotation.value();
                    // 有这个注解的都要创建对象
                    Object obj = aClass.newInstance();
                    beanMap.put(id,obj);
                }
            }catch(Exception e){
                e.printStackTrace();
            }

        });

        System.out.println(beanMap);

    }
}

运行结果:
{vipBean=com.powernode.bean.Vip@685f4c2e}
P71 END
P72 IoC注解之声明Bean的注解
P72 start:
12.2 声明Bean的注解
负责声明Bean的注解,常见的包括四个:
- @Component
- @Controller
- @Service
- @Repository
其余三个注解是@Component注解的别名
建议持久层用@Repository(dao)
业务层用@service
表示层建议用@Controller(web)
P72  end
P73 IoC注解之Spring注解的使用
P73 start  :
12.3 Spring注解的使用
如何使用以上的注解呢?
- 第一步:假如aop的依赖
- 第二步:在配置文件中添加context命名空间
- 第三步:在配置文件中指定扫描的包
- 第四步:在Bean类上使用注解

(注解不写名字,默认value=" "时,默认为类名首字母小写)

Order类中的内容:
package com.powernode.srping6.bean;

import org.springframework.stereotype.Service;

@Service //如果你把整个value属性全部省略了,bean有没有默认的名称?  有:类名首字母变小写就是bean的名字。
public class Order {
}

/**
 * 以上的这个注解@Service就相当于以下的这个配置信息:
 * <bean id = "order" class = "com.powernode.spring6.bean.Order"></bean>
 */


OrderService类中的内容:
package com.powernode.srping6.bean;

import org.springframework.stereotype.Service;

//@Service(value = "os")
//@Service("os")
@Service  //bean的名字是:orderService
public class OrderService {
}


Student类中的内容:
package com.powernode.srping6.bean;

import org.springframework.stereotype.Repository;

@Repository
public class Student {
}

User类中的内容:
package com.powernode.srping6.bean;

import org.springframework.stereotype.Component;

@Component("userBean")
public class User {
}


Vip类中的内容:
package com.powernode.srping6.bean;

import org.springframework.stereotype.Controller;

@Controller("vipBean")//如果属性名是value的haul, 这个属性名可以省略。
public class Vip {
}

/**
 * 以上的这个注解@Controller("vipBean")就相当于以下的这个配置信息:
 * <bean id = "vipBean" class = "com.powernode.spring6.bean.Vip"></bean>
 */

spring配置文件spring.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"
       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框架指定要扫描哪些包中的类 -->
    <context:component-scan base-package="com.powernode.srping6.bean" />


</beans>
测试类中的内容:
package com.powernode.spring6.test;

import com.powernode.srping6.bean.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class IoCAnnotationTest {

    @Test
    public void testBeanComponent(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User userBean = applicationContext.getBean("userBean", User.class);
        System.out.println(userBean);
        Vip vipBean = applicationContext.getBean("vipBean", Vip.class);
        System.out.println(vipBean);
        Order orderBean = applicationContext.getBean("order", Order.class);
        System.out.println(orderBean);
        Student studentBean = applicationContext.getBean("student", Student.class);
        System.out.println(studentBean);


        OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
        System.out.println(orderService);

    }

}

运行结果:
com.powernode.srping6.bean.User@60957c0f
com.powernode.srping6.bean.Vip@293a5f75
com.powernode.srping6.bean.Order@fcb4004
com.powernode.srping6.bean.Student@1dd6d4b7
com.powernode.srping6.bean.OrderService@56e8b606

P73  end
P74  IoC注解之解决多个包扫描问题
P74  start :

如果有多个包怎么办?有两种解决方案:
- 第一种:在配置文件中指定多个包,用逗号隔开。
- 第二种:指定多个包的共同父包。

上集中的 内容为此集内容一起的:
另外一个包中的文件 OrderDao类中的内容:
package com.powernode.spring6.dao;

import org.springframework.stereotype.Component;

@Component
public class OrderDao {
}


spring配置文件spring.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"
       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框架指定要扫描哪些包中的类 -->
<!--    <context:component-scan base-package="com.powernode.srping6.bean" />-->

    <!--多个包,使用逗号隔开。 -->
<!--    <context:component-scan base-package="com.powernode.spring6.bean,com.powernode.spring6.dao" />-->

    <!--多个包,也可以指定这多个包共同的父包,但是这肯定要牺牲一部分效率 -->
    <context:component-scan base-package="com.powernode.spring6" />

</beans>
测试类中的内容:
package com.powernode.spring6.test;

import com.powernode.spring6.bean.*;
import com.powernode.spring6.dao.OrderDao;
import com.powernode.spring6.bean.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class IoCAnnotationTest {

    @Test
    public void testBeanComponent(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User userBean = applicationContext.getBean("userBean", User.class);
        System.out.println(userBean);
        Vip vipBean = applicationContext.getBean("vipBean", Vip.class);
        System.out.println(vipBean);
        Order orderBean = applicationContext.getBean("order", Order.class);
        System.out.println(orderBean);
        Student studentBean = applicationContext.getBean("student", Student.class);
        System.out.println(studentBean);


        OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
        System.out.println(orderService);

        OrderDao orderDao = applicationContext.getBean("orderDao", OrderDao.class);
        System.out.println(orderDao);

    }

}

运行结果:
com.powernode.spring6.bean.User@5cdd09b1
com.powernode.spring6.bean.Vip@8c11eee
com.powernode.spring6.bean.Order@7e8dcdaa
com.powernode.spring6.bean.Student@681a8b4e
com.powernode.spring6.bean.OrderService@5cbe877d
com.powernode.spring6.dao.OrderDao@5c08c46a

P74  END
P75 spring IoC注解之选择性实例化Bean
P75 start  :
12.4  选择性实例化Bean
假设在某个包下有很多Bean,有的Bean上标注了Component,有的标注了Controller,有的标注了Service,有的标注了Repository,现在由于某种特殊业务的需要,只允许其中所有的Controller参与Bean管理,其它的都不实例化,这应该怎么办呢?

另外一个包:
A类中的内容:
package com.powernode.spring6.bean2;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

@Component
public class A {
    public A() {
        System.out.println("A的无参数构造方法执行");
    }
}
@Controller
class B{
    public B() {
        System.out.println("B的无参数构造方法执行");
    }
}

@Service
class C{
    public C() {
        System.out.println("C的无参数构造方法执行");
    }
}
@Repository
class D{
    public D() {
        System.out.println("D的无参数构造方法执行");
    }
}
@Controller
class E{
    public E() {
        System.out.println("E的无参数构造方法执行");
    }
}

spring配置文件spring.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"
       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">

    <!--
        第一种解决方案:
            use-default-filters="false"
            如果这个属性是false,表示com.powernode.spring6.bean2包下所有的带有声明Bean的注解全部失效。@Component @Controller @Service @Repository全部失效
     -->
<!--    <context:component-scan base-package="com.powernode.spring6.bean2" use-default-filters="false">-->
        <!--想让谁生效就包含谁 -->
        <!--只有@Repository  @Service 被包含进来,生效 -->
<!--        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>-->
<!--        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>-->
<!--    </context:component-scan>-->

    <!--
        第二种解决方案:
            use-default-filters="true"
            如果这个属性的值是true,表示com.powernode.spring6.bean2下的所有的带有声明Bean的注解全部生效。
             use-default-filters="true" 默认值就是true,不用写。
     -->
        <context:component-scan base-package="com.powernode.spring6.bean2" use-default-filters="true">
            <!--@Controller注解失效 -->
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>

</beans>
测试类中的内容为:
@Test
public void testChoose(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-choose.xml");
}

运行结果:
A的无参数构造方法执行
C的无参数构造方法执行
D的无参数构造方法执行

P75  end
P76  Spring IoC注解之@Value注解
P76 start  :
12.5负责注入的注解
@Component  @Controller  @Service  @Repository 这四个注解是用来声明Bean的,声明后这些Bean将被实例化。接下来我们看一下,如何给Bean的属性赋值。给Bean属性赋值需要用到这些注解:
- @Value
- @Autowired
- @Qualifier
- @Resource
12.5.1 @Value
当属性的类型是简单类型时,可以使用@Value注解进行注入。
@Value注解也可以用在方法上
@Value注解还可以用在构造方法上
@Value只负责注入简单类型
@Value可以直接用在属性上,可以用在set方法上,可以用在构造方法的形参上
(@Value不需要set方法也可以注入)

P76  end
P77 Spring IoC注解之@Value注解
P77  start :
12.5.2 @Autowired与@Qualifier
@Autowired注解可以用来注入非简单类型。被翻译为:自动连线的,或者自动装配。
单独使用@Autowired注解,默认根据类型装配。【默认是byType】
看一下它的源码:
@Target({ElementType.CONSTRUCTOR,ElementType.METHOD,ElementType.PARAMETER,ElementType.FIELD,ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired{
boolean required() default true;
}

源码中有两处需要注意:
- 第一处:该注解可以标注在哪里?
- 构造方法上
- 方法上
- 形参上
- 属性上
- 注解上
- 第二处:该注解有一个required属性,默认值是true,表示在注入的时候要求被注入的Bean必须是存在的,如果不存在则报错。如果required属性设置为false,表示注入的Bean存在或者不存在都没关系,存在的话就注入,不存在的话,也不报错。

OrderDao接口中的内容:
package org.powernode.dao;

public interface OrderDao {

    void insert();

}

OrderDaoImplForMySQL类中的内容:
package org.powernode.dao.impl;

import org.powernode.dao.OrderDao;
import org.springframework.stereotype.Repository;

@Repository("orderDaoImplForMySQL")
public class OrderDaoImplForMySQL implements OrderDao {
    @Override
    public void insert() {
        System.out.println("MySQL数据库正在保存订单信息...");
    }
}

OrderDaoImplForOracle类中的内容:
package org.powernode.dao.impl;

import org.powernode.dao.OrderDao;
import org.springframework.stereotype.Repository;

@Repository("orderDaoImplForOracle")
public class OrderDaoImplForOracle implements OrderDao {
    @Override
    public void insert() {
        System.out.println("Oracle数据库正在保存订单信息...");

    }
}


spring配置文件spring-autowired.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"
       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">

    <context:component-scan base-package="org.powernode" />


</beans>

OrderService类中的内容:
package org.powernode.service;

import org.powernode.dao.OrderDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Service("orderService")
public class OrderService {

    //@Autowired 注解使用的时候,不需要指定任何属性,直接使用这个注解即可。
    //这个注解的作用是根据类型byType进行自动装配。
   // @Autowired
    //private OrderDao orderDao;

    //如果想解决以上问题,只能根据名字进行装配。
    //@Autowired和@Qualifier联合使用,可以根据名字进行装配。

    @Autowired
    //@Qualifier("orderDaoImplForOracle")
    @Qualifier("orderDaoImplForMySQL")
    private OrderDao orderDao;

    public void generate(){
        orderDao.insert();
    }

}

测试类中的内容:
@Test
public void testAutowired(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowired.xml");
    org.powernode.service.OrderService orderService = applicationContext.getBean("orderService", org.powernode.service.OrderService.class);
    orderService.generate();

}
运行结果:
MySQL数据库正在保存订单信息...

P77  end
P78 Spring IoC注解之@Autowired注解可以出现的位置
P78  start :
Time:4h+
视频网址:
https://www.bilibili.com/video/BV1Ft4y1g7Fb?p=77&vd_source=ff898217e3612fcbdefecfdc49657ab1


 

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值