Spring注解驱动(下)

9.@PropertySource 加载配置文件

在xml中 我们加载property配置文件,是使用

<context:property-placeholder  location="classpath:spring-common.xml"/>

同样,使用注解的方式也同样可以完成

@PropertySource("classpath:jdbc.properties")//加载类路径下的jdbc.properties文件
public class PropertiesWithJavaConfig {}

10.@Autowired注解,自动装配

自动装配:

​ Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值;

@Autowired:自动注入

  1. 默认优先按照类型从容器中找对应的组件,applicationContext.getBean(BookDao.class)
  2. 如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找applicationContext.getBean("bookDao")
  3. 结合@Qualifier("bookDao")实现在通过类型转配的同时,指定id,而不是根据属性名
  4. 自动装配时,如果没有找到,就会报错,可以使用@Autowired(required=false) 属性,使用后,如果在装配时没有找到不会报错,而是null;
  5. @Primary 注解 让Spring 进行自动转配的时候 ,默认使用首选的Bean 标注@Bean注解的方法即可,如果想要指定Bean时,则可以继续使用@Qualifier来指定Bean的id

Spring还支持使用@Resource(JSR250) 和@Inject(JSR330) [java规范的注解]

@Resource:

​ 可以和Autowired注解一样实现自动装配,默认是按照组件名称进行装配的(有name属性),不支持@Primary 功能 不支持@Autowired(reqiured=false);

`@Inject`:

​ 需要导入javax.inject 的包,和Autowired注解的功能一样,但是没有 required=false的功能

另外 , @Autowired 除了可以在方法上声明使用外,构造器上,形参上都可以声明 自动装配

同时可以配合注解@Qualifier注解一起使用,value指定@Autowired注解注入Bean的ID名

11.实现xxxxAware接口 ,将Spring的容器注入到自己的类中

自定义组件想要使用Spring容器中的一些组件,例(ApplicationContext,BeanFactory..).自定义组件实现xxxAware; 在创建对象的时候 会调用接口的方法进行注入, 实现这个功能的是后置处理器,例如

ApplicationContextAware(注入ApplicationContext) ==> ApplicationContextAwareProcessor 处理器类

12. @Profile根据环境注册bean

不同的环境 ,需要注入不同的组件,就可以使用该注解,例如 在开发 测试 生产 时 注入的数据源就可能不一样,

例:

@PropertySource("classpath:/dbconfig.properties") //注入的配置文件位置
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
	
	@Value("${db.user}")
	private String user;
	
	private StringValueResolver valueResolver;
	
	private String  driverClass;
	
	
	@Bean
	public Yellow yellow(){
		return new Yellow();
	}
	
	@Profile("test") //标识为 test时 才会注入
	@Bean("testDataSource")
	public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(pwd);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
	
	
	@Profile("dev") //标识为dev时才会注入
	@Bean("devDataSource")
	public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(pwd);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud");
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
	
	@Profile("prod") //标识为prod时,才会注入
	@Bean("prodDataSource")
	public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(pwd);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515");
		
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}

	@Override
	public void setEmbeddedValueResolver(StringValueResolver resolver) {
		// TODO Auto-generated method stub
		this.valueResolver = resolver;
		driverClass = valueResolver.resolveStringValue("${db.driverClass}");
	}

}

上面的案例中,将三个数据源标识了三个标识,在对应的标识被激活时 才会注入这些对象,如果不指定,就是"default"环境.

如果环境标识注解写在类上,只有对应的环境被激活,整个配置类的Bean才会被加载.

没有标注环境标识的bean 在任何环境下都会被加载.

指定环境的方式.

  1. 使用命令行动态参数:在虚拟机参数位置加载 -Dspring.profiles.active=test.

  2. 代码的方式激活某种环境.

    AnnotationConfigApplicationContext applicationContext = 
    				new AnnotationConfigApplicationContext();
    		//1、创建一个applicationContext
    		//2、设置需要激活的环境
    		applicationContext.getEnvironment().setActiveProfiles("dev");
    		//3、注册主配置类
    		applicationContext.register(MainConfigOfProfile.class);
    		//4、启动刷新容器
    		applicationContext.refresh();
    

13. AOP基于注解的使用

spring中的aop是非常重要的功能,底层基于动态代理,可以使用xml的配置方式使用,同样也可以使用注解的方式完成:

  1. 导入aop模块 Spring AOP(spring-aspects)

  2. 定义一个业务逻辑类 ;在业务逻辑运行时讲日志进行打印

  3. 定义一个日志切面类,切面类里面的方法需要动态感知业务逻辑类运行到哪里然后执行

    相关注解:

    前置通知@Before:在目标方法运行前执行

    后置通知@After:在目标方法运行结束之后执行(无论方法正常结束还是异常结束)

    返回通知@AfterReturning: 在目标方法正常返回之后运行

    异常通知@AfterThrowing:在目标方法出现异常以后运行

    环绕通知@Around:动态代理,手动推进目标方法运行

  4. 给切面类的目标方法标注何时何地执行(切入点表达式@Pointcut)

  5. 将切面类和业务逻辑类都注入到容器中

  6. 给切面类加一个注解:@Aspect(告诉Spring那个类是切面类)

  7. 给配置类中加一个注解@EnableAspectJAutoProxy 开启基于注解的aop模式

    @Aspect
    public class LogAspects {
    	
    	//抽取公共的切入点表达式
    	//1、本类引用
    	//2、其他的切面引用
    	@Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
    	public void pointCut(){};
    	
    	//@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
    	@Before("pointCut()")
    	public void logStart(JoinPoint joinPoint){
    		Object[] args = joinPoint.getArgs();
    		System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
    	}
    	
    	@After("com.atguigu.aop.LogAspects.pointCut()")
    	public void logEnd(JoinPoint joinPoint){
    		System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
    	}
    	
    	//JoinPoint一定要出现在参数表的第一位
    	@AfterReturning(value="pointCut()",returning="result")
    	public void logReturn(JoinPoint joinPoint,Object result){
    		System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
    	}
    	
    	@AfterThrowing(value="pointCut()",throwing="exception")
    	public void logException(JoinPoint joinPoint,Exception exception){
    		System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
    	}
    
    }
    

14 Spring 事务基于注解的使用

同样Spring对于事务的控制,也可以使用注解来完成

  1. 导入 相关依赖: 数据源,数据库驱动, Spring-jdbc 模块

  2. 配置数据源

  3. 给方法上标注@Transactional 表示当前方法是一个事务方法

  4. @EnableTransactionManagement 开启基于注解的事务管理器

  5. 配置事务管理器来控制事务

         @Bean
         public PlatformTransactionManager transactionManager()

15 注解式监听器@EventListener

在spring中可以实现ApplicationListener<ApplicationEvent> 接口来实现对事件的监听,泛型为监听的事件对象, 所有的事件对象都是ApplicationEvent 的子类,所以该实现类就是监听所有的事件

同样,也可以使用的注解的方式,来指定一个方法 去监听指定的事件,例:

@Service
public class UserService {
	
	@EventListener(classes={ApplicationEvent.class})
	public void listen(ApplicationEvent event){
		System.out.println("UserService。。监听到的事件:"+event);
	}

}

该例就是让该方法去监听所有的事件

posted @ 2019-07-08 10:19  哈哈丶丶  阅读(235)  评论(0编辑  收藏  举报