Spring配置文件类实现

前言


使用spring容器配置类去替代原始的applicationContext.xml文件纯标签配置容器以及三种代理模式的简单介绍

一、配置类的使用

创建一个配置类需要注意的地方

1. 需要在配置类中类名上方需要添加注解@Configuration

在这里插入图片描述

2. 在实体类需要创建对象的格式是以方法形式进行调用创建的,也要在该实体类方法上方添加注解 @Bean,有伴随着有多个这样的注解

在这里插入图片描述

3. @Import :此注解作用在类上,把其他类导入到ioc容器中创建对象,其他类上不用加注解,主要用于集成其他框架,使用ioc管理别的框架类。

如果是外部类,不是本地类,也需要将它在spring容器配置类中存放创建类对象,需要使用@Import(),里面导入的可以是引入外部类(导入普通类)、嵌套另外一个配置类(导入其他配置类(@Configuration注解的类,类中也可以有Bean方法)(相当于配置文件中导入其他的配置文件))、导入接口ImportSelector的实现类,可以批量导入多个类、导入接口ImportBeanDefinitionRegistrar的实现类等
在这里插入图片描述

(1)@Import({Bean4.class}具体的外部引入普通类,不要需要在该类上加注解
  • 外部类
public class Bean4 {
}
  • 测试类
public class Test2 {
    public static void main(String[] args) {
        //加载配置类,创建类中定义的各个对象
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        //加载指定包以及子包下被@Controller,@Service,@Repository,@Component,@Configuration注解过的类创建对象
//        ApplicationContext context = new AnnotationConfigApplicationContext("com.entor");
  Bean4 bean4 = (Bean4) context.getBean("com.entor.entity.Bean4");
        /*与Bean4 bean4 = context.getBean(Bean4.class);等同*/
            System.out.println(bean4);
(2)@Import({BeanConfig.class},导入外部配置类,需要在注解类上加注解@Configuration,在类中类方法上加注解@Bean进行修饰
@Configuration
public class BeanConfig {
    @Bean
    public Bean7 bean7(){
        return new Bean7();
    }
    @Bean
    public Bean8 bean8(){
        return new Bean8();
    }
    @Bean
    public Bean3 bean3(){
        return new Bean3();
    }
}
(3)@Import({ImportBean.class},导入接口ImportSelector的实现类,可以批量导入多个类(springboot框架底层自动化装配使用该方法),这样从配置文件propertities中动态添加类权限包路径以及子包路径下的类名称,来动态引入外部实体类

<1>propertities配置文件代码

className=com.entor.entity.Bean5,com.entor.entity.Bean6

<2>实现ImportSelector的实现类

/**
 * 实现该接口,可以动态添加类到ioc容器中进行创建对象
 */
public class ImportBean implements ImportSelector {
    private static String[] classNames;
    static{
        Properties p = new Properties();
        try {
            p.load(ImportBean.class.getResourceAsStream("/spring.properties"));
            String className = p.getProperty("className");
            if(className!=null){
                classNames = className.split(",");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return classNames;
    }
}

<3>测试类中加载ioc中并创建实体类对象时,只能通过类名权限包以及子包路径下的类路径(属性类型)进行访问,不能使用属性id名称进行创建

public class Test2 {
    public static void main(String[] args) {
        //加载配置类,创建类中定义的各个对象
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        //加载指定包以及子包下被@Controller,@Service,@Repository,@Component,@Configuration注解过的类创建对象
//        ApplicationContext context = new AnnotationConfigApplicationContext("com.entor");
 Bean5 bean5 = (Bean5)context.getBean("com.entor.entity.Bean5");
//        Bean6 bean6 = context.getBean(Bean6.class);
        Bean6 bean6 = (Bean6)context.getBean("com.entor.entity.Bean6");
         System.out.println(bean5);
        System.out.println(bean6);
(4)@Configuration配置类通过@Import注解将ImportBeanDefinitionRegistrar接口的实现类添加其它bean到IOC容器中,@Import(MyImportBeanDefinitionRegistrar.class})

<1>外部类实体类Bean9,以及实现类MyImportBeanDefinitionRegistrar

public class Bean9 {
}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        registry.registerBeanDefinition("bean9", BeanDefinitionBuilder.rootBeanDefinition(Bean9.class).getBeanDefinition());
    }
}

<2>测试类

public class Test2 {
    public static void main(String[] args) {
        //加载配置类,创建类中定义的各个对象
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
           Bean9 bean9 = (Bean9) context.getBean("bean9");
           //通过类属性名称找到Bean9实体类,对用上MyImportBeanDefinitionRegistrar 实现类中的registry.registerBeanDefinition("bean9", BeanDefinitionBuilder.rootBeanDefinition(Bean9.class).getBeanDefinition())中对Bean9类的命名
             System.out.println(bean9);
             }
4. 对于@Configuration配置类中,对于从ioc容器中获取得到的实体类对象的一些注意事项
(1)没有相关级联的实体类,在配置类中主要是以方法名(相当于Bean标签中的id属性名称)进行创建对象的,必须是与在该类方法上注解@Bean一起使用,同样还可以增加一下原先在Bean标签中其他属性值
 /**
     * @Bean 此注解作用在方法上,相当于在配置文件中配置了一个bean标签,ioc容器会自动创建该类对象
     * <bean id="bean1" //方法名
     *       class="com.entor.entity.Bean1"
     *       init-method="init"
     *       destroy-method="destroy"
     *       lazy-init="true"
     *       scope="prototype"/>
     * @return
     */
    @Bean(initMethod = "init",destroyMethod = "destroy")//指定对象初始化方法和销毁方法
    @Lazy//延迟加载,使用该对象的时候才创建,默认是加载ioc容器时候立即创建
   // @Scope(value = "prototype")//每次调用都创建新的对象,默认是singleton单例
    public Bean1 bean1(){
        return new Bean1();
    }

测试类

  ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    Bean1 bean11 = (Bean1) context.getBean("bean1");
        Bean1 bean12 = (Bean1) context.getBean("bean1");
           System.out.println(bean11==bean12);
//如果没有设置 @Scope属性的话,默认是单例模式,结果是true,对象创建是同一个对象引用;若是修改了 @Scope(value = "prototype"),每次调用都创建新的对象,所以结果是false,对象创建不是同一个对象引用
(2)有相关级联、依赖的实体类对象,在配置类中主要是以方法名(相当于Bean标签中的id属性名称)进行创建对象的,必须是与在该类方法上注解@Bean一起使用,同样还可以增加一下原先在Bean标签中其他属性值。

因此,依赖的对象可以通过调用方法获取,或者也可以通过参数方式传递,ioc容器中只要有对应的对象会自动注入到参数中,也是DI(依赖注入)。
<1>依赖的对象可以通过调用方法获取

@Bean
public Bean2 bean2(){
        Bean2 bean2 = new Bean2();
       bean2.setBean3(bean3());//使用方法调用拿到的是ioc创建好的对象,默认是单例对象
       // bean2.setBean3(new Bean3());//创建一个新的对象
        return bean2;
    }

<2>通过参数方式传递

 @Bean
    public Bean2 bean22(Bean3 bean3){
        return new Bean2(bean3);
    }

两者的测试类

     //加载配置类,创建类中定义的各个对象
 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
 Bean2 bean2 = (Bean2) context.getBean("bean2");
        Bean2 bean22 = (Bean2) context.getBean("bean22");
         System.out.println(bean2);
        System.out.println(bean22);
        //两者的对象引用是相同的

<3>如果在有被依赖的对象Bean2中,返回的是一个新的依赖对象Bean3,这时返回的相同的被依赖对象Bean2中的Bean3对象就不一样了

  @Bean
    public Bean2 bean2(){
        Bean2 bean2 = new Bean2();
//        bean2.setBean3(bean3());//使用方法调用拿到的是ioc创建好的对象,默认是单例对象
        bean2.setBean3(new Bean3());//创建一个新的对象
        return bean2;
    }
    /**
    此时两个Bean3对象就不一样
    */
  @Bean
    public Bean2 bean22(Bean3 bean3){
        return new Bean2(bean3);
    }
5.对于特殊指定层的注解 @Controller、@Service、@Repository使用
(1)@Repository注解在Dao层上
@Repository
public class UserDaoImpl implements UserDao {
    @Override
    public void delete() {
        System.out.println("删除用户信息");
    }
}
(2)@Service注解在Service层上
@Service(value = "userService")
public class UserServiceImpl implements UserService {

    @Autowired//需要加Autowired来获取相关其他属性名称,如userDao
    private UserDao userDao;
    @Override
    public void delete() {
        userDao.delete();
    }
}
(3)@Controller注解在控制器层面上
@Controller
public class UserController {
    @Autowired()//需要加Autowired来获取相关其他属性名称,如userService
    private UserService userService;
    public void delete(){
        userService.delete();
    }
}
(4)xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd"
    <context:component-scan base-package="com"/>
    <!--base-package="com"包下面的包四种注解标注的类Controller-->
    </beans>
(5)测试类
public class Test {
    public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
       UserController controller = (UserController)context.getBean("userController");
        controller.delete();

    }
}

二、三种代理模式

1.静态代理模式
  • 目标对象接口
public interface UserDao {
    public void delete();
}
  • 目标对象实现类
public class UserDaoImpl implements UserDao{
    @Override
    public void delete() {
        System.out.println("删除用户信息");
    }
}
  • 代理对象实现类,从不破坏目标对象的原有代码功能上,添加新的功能
public class Proxy implements UserDao {
    private UserDao userDao;
    public Proxy(UserDao userDao){
        this.userDao=userDao;
    }
    @Override
    public void delete() {
        check();
        userDao.delete();
        log();
    }
    public void check(){
        System.out.println("检验");
    }
    public void log(){
        System.out.println("日志");
    }
}
  • 测试类
public class Test {
    public static void main(String[] args) {
        //目标对象
        UserDao userDao=new UserDaoImpl();
        userDao.delete();
        System.out.println("====================");
        //使用代理类对象,实际调用的还是目标对象方法,
        // 额外的增加了其他功能
        Proxy proxy = new Proxy(userDao);
        proxy.delete();
    }

}

缺点:代理对象跟目标对象实现统一接口,目标对象接口发生改变,代理对象也跟着改变

2.JDK动态代理模式
  • 目标对象接口
public interface UserDao {
    public void delete();
    public void update();
    public void query();
}
  • 目标对象实现类
public class UserDaoImpl implements UserDao {
    @Override
    public void delete() {
        System.out.println("删除用户信息");
    }

    @Override
    public void update() {
        System.out.println("更新用户信息");
        throw new RuntimeException("exception");
    }

    @Override
    public void query() {
        System.out.println("查询用户信息");
    }
}
  • 代理对象实现类,从不破坏目标对象的原有代码功能上,添加新的功能,通过反射动态调用目标对象的方法,不会随着目标对象的方法改变而修改代码;但是要求目标对象必须是实现接口
/**
 * jdk动态代理,通过反射动态调用目标对象的方法,不会随着目标对象的方法改变而修改代码
 * 但是要求目标对象必须是实现接口
 */
public class JDKProxy implements InvocationHandler {
    private Object targetObject;
    public Object createProxyInstance(Object targetObject){
        this.targetObject=targetObject;
       return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),
                this.targetObject.getClass().getInterfaces(),this);

    }

    /***
     *
     * @param proxy:代理对象
     * @param method:目标对象的方法
     * @param args:目标对象的方法参数值
     * @return:目标对象的方法返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法名包括delete或者update的需要调用check方法
        if (method.getName().contains("delete")||method.getName().contains("update")){
            check();//前置通知
        }
        Object obj=null;
        try{
            //动态调用目标对象的方法
           obj = method.invoke(this.targetObject, args);
        }catch (Exception e){
            e.printStackTrace();
            ex();//例外通知
        }finally {
            fin();//最终通知
        }
        //动态调用目标对象的方法
       /* Object obj = method.invoke(this.targetObject, args);*/
        log();//后置通知
        return obj;

    }
    public void check(){
        System.out.println("安全校验");
    }
    public void log(){
        System.out.println("日志记录");
    }
    public void ex(){
        System.out.println("系统发生异常");
    }
    public void fin(){
        System.out.println("最终要执行的方法");
    }
}
  • 测试类
public class Test {
    public static void main(String[] args) {
        //目标对象
        UserDao userDao=new UserDaoImpl();
        userDao.delete();
        //userDao.update();
        userDao.query();
        System.out.println("====================");
        //使用代理类对象,实际调用的还是目标对象方法,
        // 额外的增加了其他功能
        JDKProxy jdkProxy = new JDKProxy();
        UserDao proxy=(UserDao) jdkProxy.createProxyInstance(userDao);
        proxy.delete();
        System.out.println("===============");
        proxy.update();
        System.out.println("===============");
        proxy.query();
        System.out.println("===============");
      /*  StudentDao studentDao =(StudentDao) jdkProxy.createProxyInstance(new StudentDao());
        studentDao.delete();*/
        /*目标对象没有实现接口,无法实现jdk动态代理,报错*/
    }
}
3.Cglib动态代理模式
  • 目标对象接口
public interface UserDao {
    public void delete();
    public void update();
    public void query();
}
  • 目标对象实现接口类
public class UserDaoImpl implements UserDao {
    @Override
    public void delete() {
        System.out.println("删除用户信息");
    }

    @Override
    public void update() {
        System.out.println("修改用户信息");
       // throw new RuntimeException("exception");
    }

    @Override
    public void query() {
        System.out.println("查询用户信息");
    }
}
  • 代理对象实现类,从不破坏目标对象的原有代码功能上,添加新的功能
public class CjlibProxy implements MethodInterceptor {
    //要代理的目标对象
    private Object targetObject;
    public Object createProxyInstance(Object targetObject){
        this.targetObject=targetObject;
        //该类用于生成代理对象
        Enhancer enhancer=new Enhancer();
        //设置父类
        enhancer.setSuperclass(this.targetObject.getClass());
        //设置回调对象为本身
        enhancer.setCallback(this);
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //方法名包括delete或者update的需要调用check方法
        if (method.getName().contains("delete")||method.getName().contains("update")){
            check();//前置通知
        }
        Object obj=null;
        try{
            //动态调用目标对象的方法
            obj = method.invoke(this.targetObject,objects);
        }catch (Exception e){
            e.printStackTrace();
            ex();//例外通知
        }finally {
            fin();//最终通知
        }
        //动态调用目标对象的方法
        /* Object obj = method.invoke(this.targetObject, args);*/
        log();//后置通知
        return obj;

    }
    public void check(){
        System.out.println("安全校验");
    }
    public void log(){
        System.out.println("日志记录");
    }
    public void ex(){
        System.out.println("系统发生异常");
    }
    public void fin(){
        System.out.println("最终要执行的方法");

    }
}

  • 测试类
public class Test {
    public static void main(String[] args) {
        //目标对象
        UserDao userDao = new UserDaoImpl();
        //cglib代理实现了接口的目标对象
        CjlibProxy proxy = new CjlibProxy();
        UserDao userDao1 = (UserDao) proxy.createProxyInstance(userDao);
        System.out.println("===============");
        userDao1.delete();
        System.out.println("===============");
        userDao1.update();
        System.out.println("===============");
        userDao1.query();
        //cglib代理没有实现接口的目标对象
        StudentDao studentDao = (StudentDao)proxy.createProxyInstance(new StudentDao());
        System.out.println("===============");
        studentDao.delete();
    }
}

总结


1. @Configuration:此注解作用在类上,相当于该类是一个applicationContext.xml配置文件,@Import:此注解作用在类上,把其他类导入到ioc容器中创建对象,主要用于集成其他框架,使用ioc管理别的框架,其他的类上不用加注解,有四种方式导入

1、导入普通类
2、导入其他配置类(@Configuration注解的类,类中也可以有Bean方法),
3. 相当于配置文件中导入其他的配置文件
4.导入接口ImportSelector的实现类,可以批量导入多个类(springboot框架底层自动化装配使用该方法)

2.@Bean:此注解作用在方法上,有多个类对象,就要配置多个注解bean相当于在配置文件中配置了一个bean标签,ioc容器会自动创建该类对象

3.@Bean(initMethod = “init”,destroyMethod = “destroy”), @Lazy//延迟加载,使用该对象的时候才创建,默认是加载ioc容器时候立即创建,@Scope(value = “prototype”)//每次调用都创建新的对象,默认是singletion单例;

等价于
标签中的配置 <bean id=“bean1” class=“com.entity.Bean1” //包名路径; init-method=“init” //类初始化;destroy-method=“destroy” //类销毁;lazy-init=“true” //加载时候创建对象scope=“prototype”/>//单例模式默认

3.三种代理模式特点:

  • 代理模式三种:
  • 1、静态代理:代理对象跟目标对象实现统一接口,目标对象接口发生改变,
  • 代理对象也跟着改变
  • 2、jdk动态代理:通过反射动态调用目标对象的方法,代理对象不随着目标对象接口发生改变而改变,
  • 但是前提是只能代理实现了接口的目标对象
  • 3、cglib动态代理:通过反射动态调用目标对象的方法,代理对象不随着目标对象接口发生改变而改变,可以实现任何目标对象
  • 动态代理,可以在反射动态调用方法执行前后添加通知(方法或功能),包括有:
  • 1、前置通知(方法调用之前)
  • 2、后置通知(方法调用之后)
  • 3、环绕通知(方法调用之前后包裹)
  • 4、例外通知(方法调用发生异常,catch)
  • 5、最终通知(方法调用之后无论如何都执行,finally)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值