Spring应用——注解编程

基于注解的方式实现

1.配置注解

注解名称说明
@Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
@ComponentScan在配置类上添加 @ComponentScan 注解。该注解默认会扫描该类所在的包下所有的配置类,相当于之前的 context:component-scan
@Scope用于指定scope作用域的(用在类上)
@Lazy表示延迟初始化
@ConditionalSpring4开始提供,它的作用是按照一定的条件进行判断,满足条件给容器注册Bean。
@Profile本质上就是一个条件注解的实现,它可以通过不同环境返回不同的实例对象,常用于数据源切换等。
@Import导入外部资源
生命周期控制@PostConstruct用于指定初始化方法(用在方法上)
@PreDestory用于指定销毁方法(用在方法上)
@DependsOn:定义Bean初始化及销毁时的顺序

1.1 @Configuration

把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。

@Configuration
public class JavaConfig {
}

1.2 @ComponentScan

package com.gupaoedu;

import com.gupaoedu.controller.UserController;
import com.gupaoedu.dao.IUserDao;
import com.gupaoedu.dao.impl.UserDaoImpl;
import com.gupaoedu.service.IUserService;
import com.gupaoedu.service.impl.UserServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;

/**
 *  @ComponentScan 如果不去指定扫描的路径,默认是会扫描当前目录及其子目录下的所有的
 *                  被@Componenet @Controller @Service @Repository标注的类型
 */
@Configuration
/*@ComponentScan(value = {"com.gupaoedu.controller"}
,useDefaultFilters = false
        ,includeFilters = {@ComponentScan.Filter(Controller.class)})*/
@ComponentScans({
        @ComponentScan(value = {"com.gupaoedu.controller"}
                ,useDefaultFilters = false
                ,includeFilters = {@ComponentScan.Filter(Controller.class)})
        ,@ComponentScan(value = {"com.gupaoedu.service","com.gupaoedu.dao"}
                ,useDefaultFilters = true
                ,excludeFilters = {@ComponentScan.Filter(Controller.class)})
})
public class JavaConfig {

}

1.3 @Scope

作用域说明
prototype每次请求,都是一个新的Bean( java原型模式)
singletonbean是单例的(Java单例模式)
request在一次请求中,bean的声明周期和request同步
sessionbean的生命周期和session同步

默认的情况是 singleton

1.4 @Lazy

Spring中Bean的作用域默认是单例的,单例对象默认在IoC容器创建之后就进行创建并放入到IoC容器中。使用@Lazy注解则可以让单例对象在真正用到时才进行创建。

1.5 @Conditional

@Conditional注解 通过重写matches方法来动态实现是否加载某类型

package com.gupaoedu.conditional;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class ConditionalOnBean implements Condition {
    /**
     *
     * @param conditionContext
     * @param annotatedTypeMetadata
     * @return
     *    true 表示IoC容器加载该类型
     *    false 表示IoC容器不加载该类型
     */
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return true;
    }
}
package com.gupaoedu;

import com.gupaoedu.conditional.ConditionalOnBean;
import com.gupaoedu.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JavaConfig {

    /**
     * @Conditional(ConditionalOnBean.class)
     *    是一个条件注解 表示如果ConditionalOnBean中的matches方法返回true就加载
     *        返回false就不加载
     * @return
     */
    @Bean
    @Conditional(ConditionalOnBean.class)
    public User user(){
        return new User();
    }

    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanName:beanDefinitionNames){
            System.out.println(beanName);
        }
    }
}

Spring中已实现的Conditional注解的类

@Conditional扩展注解作用(判断是否满足当前指定条件)
@ConditionalOnJava系统的Java版本是否符合要全
@ConditionalOnBean容器中存在指定的Bean
@ConditionalOnMissingBean容器中不存在指定的Bean
@ConditionalOnExpression满足SpEL表达式
@ConditionalOnClass系统中有指定的类
@ConditionalOnMissingClass系统中没有指定的类
@ConditionalOnSingleCandidate容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty系统中指定的属性是否有指定的值
@ConditionalOnResource类路径下是否存在指定的资源文件
@ConditionalOnWebApplication当前是Web环境
@ConditionalOnNotWebApplication当前不是Web环境
@ConditionalOnJndiJNDI存在指定项

1.6 @Profile

根据不同的环境返回不同的对象

package com.gupaoedu.pojo;

 @Data
public class GpDataSource {

    private String username;

    private String password;

    private String url;

    public GpDataSource(String username, String password, String url) {
        this.username = username;
        this.password = password;
        this.url = url;
    }

    @Override
    public String toString() {
        return "GpDataSource{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", url='" + url + '\'' +
                '}';
    }

    public GpDataSource() {
    }
}
package com.gupaoedu;

import com.gupaoedu.conditional.ConditionalOnBean;
import com.gupaoedu.conditional.ConditionalOnClass;
import com.gupaoedu.pojo.GpDataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;

@Configuration
public class JavaConfig {

    @Bean
    @Profile("pro") // 其实Profile注解本质上就是Conditional的一种实现
    public GpDataSource proDataSource(){
        GpDataSource ds = new GpDataSource("root","123","192.168.11.190");
        return ds;
    }

    @Bean
    @Profile("dev")
    public GpDataSource devDataSource(){
        GpDataSource ds = new GpDataSource("admin","456","192.168.12.190");
        return ds;
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
        // 通过设置不同环境返回不同对象
        ac.getEnvironment().setActiveProfiles("dev");
        ac.register(JavaConfig.class);
        ac.refresh();
        System.out.println(ac.getBean(GpDataSource.class));
    }
}

1.7 @Import

将某个类导入到IoC容器中

1.7.1 静态导入

在这里插入图片描述

1.7.2 动态导入 - ImportSelector
public class GpImportSelector implements ImportSelector {

    /**
     *
     * @param annotationMetadata
     * @return
     *    IoC 要加载的类型的全路径的字符串数组
     */
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 在此处实现不同的业务逻辑控制
        return new String[]{LoggerService.class.getName(),CacheService.class.getName()};
    }
}
1.7.3 动态导入 - ImportBeanDefinitionRegistrar
package com.gupaoedu.demo;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class GpImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     *
     * @param annotationMetadata
     * @param beanDefinitionRegistry IoC容器中管理对象的一个注册器
     */
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        // 需要将添加的对象包装为一个RootBeanDefinition对象
        RootBeanDefinition cache = new RootBeanDefinition(CacheService.class);
        beanDefinitionRegistry.registerBeanDefinition("cache",cache);

        RootBeanDefinition logger = new RootBeanDefinition(LoggerService.class);
        beanDefinitionRegistry.registerBeanDefinition("logger",logger);
    }
}

1.8 @PostConstruct @PreDestory @DependsOn

@PostConstruct 用于指定初始化方法(用在方法上)
@PreDestory 用于指定销毁方法(用在方法上)
@DependsOn 指定实例化对象的先后顺序

@Component
// Person的实例化依赖于User对象的实例化,也就是User先于Person实例化
@DependsOn({"user"})
public class Person {
    public Person(){
        System.out.println("Person 构造方法执行了...");
    }
}

2.赋值注解

注解名称说明
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Service用于标注业务层组件
@Controller用于标注控制层组件
@Repository用于标注数据访问组件,即DAO组件。
@Value普通数据类型赋值
@Autowired默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用
@PropertySource读取配置文件赋值
@Qualifier如存在多个实例配合使用
@Primary自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。

2.1 @Component @Controller @Service @Repository

@Component:泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注;
@Controller:用于标注控制层组件;
@Service:用于标注业务层组件;
@Repository:用于标注数据访问组件,即DAO组件。

2.2 @Value

package com.gupaoedu.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

@Component
@Data
public class User {

    @Value("bobo") // 注入普通的字符串
    private String userName ;

    @Value("#{systemProperties['os.name']}")
    private String systemPropertiesName; // 注入操作系统的信息

    @Value("#{T(java.lang.Math).random()*100}")
    private double randomNumber; // 注入表达式的结果

    @Value("#{person.personName}")
    private String fromPersonName; // 注入其他Bean的属性


    @Value("classpath:test.txt")
    private Resource resourceFile;

    @Value("http://www.baidu.com")
    private Resource baiduFile;
}

2.3 @Autowired

默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用

2.4 @Qualifier

如存在多个实例配合使用

2.5 @PropertySource

在Java配置类中通过@PropertySouce注解来显示的引入属性文件

@Configuration
@ComponentScan("com.gupaoedu")
// 显示的指定要加载的属性文件
@PropertySource({"classpath:spring-db.properties"})
public class JavaConfig {

}

在这里插入图片描述

2.6 @Primary

自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常

2.7 @Resource

默认按名称装配,当找不到与名称匹配的bean才会按类型装配。

3. 切面注解

注解名称说明
@EnableTransactionManagement添加对事物管理的支持
@Transactional配置声明式事物
@EnableAspectJAutoProxy启用对AspectJ的支持
@Aspect声明为切面类
通知类型@Before:前置通知,目标方法执行之前调用。
@AfterReturning:后置通知,目标方法执行完成之后调用。
@Around:环绕通知,目标方法执行前后都会调用方法,且能增强结果。
@AfterThrowing:异常通知,目标方法出现异常调用。
@After:最终通知,无论程序执行是否正常,该通知都会执行。类似于try…catch中finally代码块。

3.1 @EnableTransactionManagement

3.2 @Transactional

3.3 @EnableAspectJAutoProxy

@Configuration
@EnableAspectJAutoProxy // 放开AspectJ的使用
@ComponentScan
public class JavaConfig {


    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
        IUserService bean = ac.getBean(IUserService.class);
        bean.fun1();
    }
}

3.4 @Aspect

package com.gupaoedu.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect // 显示的表明当前类是一个切面类
@Component // 将该对象加载到IoC容器中
public class MyAspectJ01 {

    /**
     * 要增强目标对象的方法
     *     指定目标对象
     *     切入点表达式
     */
    @Before("execution(* com.gupaoedu.service.impl.*.fun2(..))")
    public void aspectMethod01(){
        System.out.println("before ....");
    }
}

3.5 通知类型

package com.gupaoedu.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspectJ02 {

    /**
     * 前置通知
     */
    @Before("execution(* com.gupaoedu.service.impl.*.*(..))")
    public void before(){
        System.out.println("before ...");
    }

    /**
     * 后置通知  获取返回结果
     * @param res
     */
    @AfterReturning(value = "within(com.gupaoedu.service.impl.*)",returning = "res")
    public void afterReturning(Object res){
        System.out.println("后置通知..." + res);
    }

    /**
     * 环绕通知
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around(value = "within(com.gupaoedu.service.impl.*)")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("目标对象before....");
        Object[] args = proceedingJoinPoint.getArgs();

        Object res = proceedingJoinPoint.proceed(); // 目标对象方法执行
        System.out.println("目标对象after...." + res);
        return res;
    }

    /**
     * 异常通知
     * @param ex
     */
    @AfterThrowing(value = "within(com.gupaoedu.service.impl.*)",throwing = "ex")
    public void afterThrowing(Exception ex){
        System.out.println("异常通知产生了..." + ex);
    }

    /**
     * 最终通知
     */
    @After(value = "within(com.gupaoedu.service.impl.*)")
    public void after(){
        System.out.println("最终通知...");
    }
}
3.5.1 切入点表达式
表达式类型说明
execution定位到目标对象的方法上
within定位到具体的类型上
this代理对象的类型
target目标对象的类型
args参数的类型
@args传入的参数有被该注解修饰
@within类型修饰的注解
@annotation方法修饰的注解

execution表达式
语法: execution([访问权限类型] 返回值类型 [全限定类名] 方法名(参数名) [抛出的异常类型])

符合含有
*0到多个符合
方法参数中表示任意个参数,用在报名后表示当前包及其子包
+用在类名后表示当前类及其子类,用在接口后表接口及其实现

示例:

execution(public * *(. .))
指定切入点为:任意公共方法。
execution(* set *(. .))
指定切入点为:任何一个以“set”开始的方法。
execution(* com.xyz.service.*.*(. .))
指定切入点为:定义在service包里的任意类的任意方法。
execution(* com.xyz.service. .*.*(. .))
指定切入点为:定义在service包或者子包里的任意类的任意方法。“..”出现在类名中时,
后面必须跟“*”,表示包、子包下的所有类。
execution(* *.service.*.*(. .))
指定只有一级包下的serivce子包下所有类(接口)中的所有方法为切入点
execution(* *. .service.*.*(. .))
指定所有包下的serivce子包下所有类(接口)中的所有方法为切入点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值