Spring IoC注解

一、回顾反射机制

反射的调用三步:1)获取类。2)获取方法。3)调用方法

调用方法:调用哪个对象,哪个方法,传什么参数,返回什么值。

方法(Do)类:

package test1;
public class Do {
    //定义方法
    public void doSome(){
        System.out.println("doSome()方法执行");
    }
    public String doSome(String s){
        System.out.println("doSome(String s)方法执行");
        return s;
    }
    public String doSome(String s,int i){
        System.out.println("doSome(String s,int i)方法执行");
        return s+i;
    }
}

测试类:

public class test1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //先获取类
       Class clazz=Class.forName("test1.Do");
       //再获取方法
       Method m= clazz.getDeclaredMethod("doSome", String.class, int.class);
       //调用方法
        //四要素:调用哪个对象,哪个方法,传什么参数,返回什么值
        //创建对象
       Object obj= clazz.newInstance();
       Object value= m.invoke(obj,"张三",23);
       System.out.println(value);
    }
    }

SpringDI核心实现

一个小练习:为手写Spring框架打前提

有这么一个类,类名叫:test1.Student,这个类符合javabean构造,还知道这个类中有一个属性叫age,且age类型为int类型,使用反射机制调用set方法,给Student对象的age属性赋值。

一个完整的javabean的Student类:

package test1;
public class Student {
    private String name;
    private int age;
    public Student(){

    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 测试类:

public class test1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //有这么一个类,类名叫:test1.Student
        //这个类符合javabean构造
        //还知道这个类中有一个属性叫age,且age类型为int类型
        //使用反射机制调用set方法,给Student对象的age属性赋值
        String className="test1.Student";//类名
        String propertyName="age";//属性
        //获取类
        Class clazz=Class.forName(className);
        //获取方法名
        String name="set"+propertyName.toUpperCase().charAt(0)+propertyName.substring(1);
        //获取方法
       Method m=clazz.getDeclaredMethod(name,int.class);
       //创建对象
       Object obj=clazz.newInstance();
       //调用方法
        m.invoke(obj,23);//无返回值类型
        System.out.println(obj);

    }
    }

org:框架的开发人员

com:框架的使用者

二、Spring IoC注解式开发

1.注解

2.反射注解

先创建一个注解,并定义其属性:

package com.hei;
import javax.lang.model.element.Element;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//注解
@Target(ElementType.TYPE)//用于描述类、接口的注解
@Retention(RetentionPolicy.RUNTIME)//利用保留在class文件中,也可以用反射机制
public @interface Component {
    //注解属性
    //String属性类型
    //value属性名
    String value();
}

 创建一个类,将注解附上:

package com.hei;
//value可以省略
@Component(value = "userbean")
public class User {

}

主函数利用反射机制:

现获取注解所在的类,再判断这个类上是否有注解,若存在,则获取注解。

public class test {
    public static void main(String[] args) throws ClassNotFoundException {
        //利用反射机制获取注解属性
        //现获取注解所在类
        Class clazz=Class.forName("com.hei.User");
        //判断类上有没有这个注解
       if(clazz.isAnnotationPresent(Component.class)){
           //获取注解
           Component com= (Component) clazz.getAnnotation(Component.class);
           System.out.println(com.value());
       }
    }
}

3.组件扫描原理

是扫描包下的类是否带了注解

  类加载器

Java类加载器(Class Loader)是Java虚拟机(JVM)的一部分,负责将类的字节码加载到内存中,并将其转换为可执行的Java对象。根据类的全限定名(包括包路径和类名),定位并读取类文件的字节码。

public class ClassLoaderExample {
    public static void main(String[] args) throws ClassNotFoundException {
        // 使用系统类加载器加载并实例化一个类
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        Class<?> clazz = classLoader.loadClass("com.example.MyClass");
        MyClass myObject = (MyClass) clazz.newInstance();
        
        // 调用加载的类的方法
        myObject.sayHello();
    }
}
class MyClass {
    public void sayHello() {
        System.out.println("Hello, World!");
    }
}

输出了:Hello,world. 

题目

给一个包,将包下带有注解的类,扫描出来。

先创建一个注解,并定义其属性:

package com.hei.Annotion;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//注解
@Target(ElementType.TYPE)//用于描述类、接口的注解
@Retention(RetentionPolicy.RUNTIME)//利用保留在class文件中,也可以用反射机制
public @interface Component {
    //注解属性
    //String属性类型
    //value属性名
    String value();
}

创建带有注解的类和不带有注解的类:

package com.hei.bean;
import com.hei.Annotion.Component;
@Component("userbean")
public class User {

}

package com.hei.bean;
public class Vip {
}

package com.hei.bean;
import com.hei.Annotion.Component;
@Component("oderbean")
public class Order {
}

测试类:

package com.hei.client;
import com.hei.Annotion.Component;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class test {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        Map<String,Object> hm=new HashMap<>();
        //只知道包名,要扫描包下的带有注释的类
        String Package="com.hei.bean";//包名
        //要把这个包名替换成路径
        String Pacpath=Package.replaceAll("\\.","/");
        //System.out.println(Pacpath);
        //运用类加载器,获取路径
       URL url= ClassLoader.getSystemClassLoader().getResources(Pacpath).nextElement();
       //获取绝对路径
        String path=url.getPath();
        //获取绝对路径下的文件
        File file=new File(path);
        File[] files=file.listFiles();//获取路径下所有内容
        for(File f:files){
            String name=f.getName();
            String s = name.split("\\.")[0];
            //System.out.println(s);
            String ClassName=Package+"."+s;//获取文件所在位置包名加类名
            //利用反射机制,获取包名
            Class clazz=Class.forName(ClassName);
            if(clazz.isAnnotationPresent(Component.class)){
               Component com= (Component) clazz.getAnnotation(Component.class);
               String id= com.value();
               Object obj= clazz.newInstance();
                hm.put(id,obj);
            }
        }
        System.out.println(hm);
    }
}

4.声明Bean的注解 

后面三个注解都是基于第一个注解。

5.Spring注解使用

第一步:加入依赖在引入spring-context依赖中就已包含。

配置文件(spring.xml):

<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.hei.bean"/>
</beans>

扫描的类:

package com.hei.bean;
import org.springframework.stereotype.Component;
@Component("userbean")
public class User {
}

package com.hei.bean;
import org.springframework.stereotype.Service;
@Service("vipbean")
public class Vip {
}

package com.hei.bean;
import org.springframework.stereotype.Controller;
@Controller//将value全部省略,bean名为类名变小写
public class Order {
}

测试类:

package com.hei;
import com.hei.bean.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
    @org.junit.Test
    public void test(){
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring.xml");
        User u= applicationContext.getBean("userbean",User.class);
        System.out.println(u);
        Vip v= applicationContext.getBean("vipbean",Vip.class);
        System.out.println(v);
        Order o=applicationContext.getBean("order",Order.class);
        System.out.println(o);
    }
    }

若有多个包:

6.选择性实例化Bean

第一种实现方法:

先定义带有注解的类:

package com.hei.bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

@Controller
public class A {
    public A(){
        System.out.println("A的无参构造执行");
    }
}
@Component
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的无参构造执行");
    }
}

 spring.xml配置文件中,use-deafult-filters=false使全部注解失效,通过context:include-filter type使想要的注解生效。

<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.hei.bean" use-default-filters="false">
       <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>
     
</beans>

测试类:

public class Test {
    @org.junit.Test
    public void test(){
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring.xml");
    }
    }

第二种方法:

通过context:exclude-filter type=" "使的注解失效。

 <context:component-scan base-package="com.hei.bean" >
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

7.负责注入的注解

1) @value注解

当属性类型为简单类型时,可以使用@Value注解进行注入,@Value可以用在定义属性上,也可用在set方法上,也可以用在构造方法的形参上。

Student类:

package com.hei.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Student {
    @Value("张三")
    private String name;
    @Value("25")
    private int age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

spring.xml:

<context:component-scan base-package="com.hei.bean"></context:component-scan>

测试类:

public class Test {
    @org.junit.Test
    public void test(){
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring.xml");
        Student s=applicationContext.getBean("student",Student.class);
        System.out.println(s);
    }
    }

2)@Autowired

@Autowired注解使用的时候,不需要指定任何属性,直接使用即可。

@Autowired可以用在定义属性上,也可用在set方法上,也可以用在构造方法的形参上。

@Autowiredhe@Qualifier联合使用,可根据名字自动装配。

接口:

package com.hei.bean;
public interface Order {
     void insert();
}

连接接口的类:

import com.hei.bean.Order;
import org.springframework.stereotype.Repository;

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

调用方法的类:

package com.hei.bean.Service;
import com.hei.bean.Dao.OrderDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("orderService")
public class OrderService {
    @Autowired
    private OrderDao orderDao;
    public void save(){
        orderDao.insert();
    }
}

spring.xml:

<context:component-scan base-package="com.hei.bean"></context:component-scan>

 测试类:

public class Test {
    @org.junit.Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        OrderService o= applicationContext.getBean("orderService", OrderService.class);
        o.save();
    }
    }

3)@Resource

引入resource依赖:

 <dependency>
            <groupId>jakarta.annotation</groupId>
            <artifactId>jakarta.annotation-api</artifactId>
            <version>2.1.1</version>
        </dependency>

 接口:

package com.hei.bean;
public interface Order {
     void insert();
}

连接接口的类:

package com.hei.bean.Dao;
import com.hei.bean.Order;
import org.springframework.stereotype.Repository;

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

调用方法的类:

package com.hei.bean.Service;
import com.hei.bean.Dao.OrderDao;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

@Service("orderService")
public class OrderService {
    @Resource(name = "orderDao")
    private OrderDao orderDao;
    public void save(){
        orderDao.insert();
    }
}

spring.xml:

<context:component-scan base-package="com.hei.bean"></context:component-scan>

测试类:

public class Test {
    @org.junit.Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        OrderService o= applicationContext.getBean("orderService", OrderService.class);
        o.save();

    }
    }

8.全注解式开发

全注解式开发:不再使用配置文件,而是编写一个类替代配置文件。

其他的接口、类和上面的例子一样。

SpringConfig类:

package com.hei.bean;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//编写一个类代替Spring框架的配置文件
@Configuration
@ComponentScan({"com.hei.bean.Dao","com.hei.bean.Service"})
public class SpringConfig {
}

测试类:

public class Test {
    @org.junit.Test
    public void T(){
        AnnotationConfigApplicationContext a=new AnnotationConfigApplicationContext(SpringConfig.class);
        OrderService o= a.getBean("orderService",OrderService.class);
        o.save();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值