Spring注解版

# Spring注解版

 

## 一、@Configuration和@Bean注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class Person {
 
private String name;
private Integer age;
 
public Person() {
}
 
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
 
public String getName() {
return name;
}
 
public void setName(String name) {
this.name = name;
}
 
public Integer getAge() {
return age;
}
 
public void setAge(Integer age) {
this.age = age;
}
 
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

  

配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class ApplicationConfig {
 
@Bean
public Person person(){
return new Person("lisi",18);
}
/*@Bean("person02")
public Person person(){
return new Person("lisi",20);
}*/
 
}

  

 

对比配置文件:

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<bean id = "person" class="com.wzs.entity.Person">
<property name="name" value="zs"/>
<property name="age" value="18"/>
</bean>
</beans>
复制代码

 

 

 

1.@Configuration:标注在类上,则表明该类是一个配置类,作用类似xml。

2.@Bean:

​ 1)标注在方法上,则表明注册一个组件到ioc容器中。

​ 2)方法的返回值类型代表要注册到容器的类型,代表bean中的class

​ 3)方法名代表注册到ioc的bean的id

​ 4)@Bean写上字符串则可以该表bean的id

 

配置类测试:

public class ConfigTest {
public static void main(String[] args) {
ApplicationContext ioc = new AnnotationConfigApplicationContext(ApplicationConfig.class);
Person bean = ioc.getBean("person");
System.out.println(bean);//Person{name='lisi', age=18}
}
}

 

 

## 二、@ComponentScan注解

1.@ComponentScan注解作用类似于xml中的<context:component-scan>标签,即作用是包扫描。

2.该注解写在配置类上

3.格式:@ComponentScan(value = "指定要扫描的包名")

4.配置包扫描的规则:

1)excludeFilters:排除

配置类方式:

@ComponentScan(value ="com.wzs" ,excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)
})
//excludeFilters:表示排除规则
//type:指定排除的类型
//value:指定排除的具体类型

 

xml方式:

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

 

2)includeFilters:只包含 注意使用时还要加上useDefaultFilters =false来禁用默认规则

配置类的方式:

@ComponentScan(value ="com.wzs" ,includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)
},useDefaultFilters =false )
//includeFilters:表示只包含规则
//type:指定包含的类型
//value:指定包的具体类型

xml方式:

<context:component-scan base-package="com.wzs" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

 

3)@ComponentScan.Filter的type:指定类型

 

复制代码
type可以取的值有:
FilterType.ANNOTATION;(掌握):代表扫描带有注解的

FilterType.ASSIGNABLE_TYPE;(掌握):代表扫描指定类的

FilterType.ASPECTJ;

FilterType.REGEX;

FilterType.CUSTOM;(掌握):代表扫描自定义规则类的
复制代码

 

FilterType.ASSIGNABLE_TYPE:

@ComponentScan(value ="com.wzs" ,includeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = com.wzs.service.MyService.class)
},useDefaultFilters =false )

FilterType.CUSTOM:

使用FilterType.CUSTOM前提是要写自定义规则的类,且该类要实现TypeFilter接口:

复制代码
public class Myfilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取扫描当前类的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前正在扫描类的资源路径
Resource resource = metadataReader.getResource();
//获取扫描类的全类名
String className = classMetadata.getClassName();
//将指定的类加载到ioc容器中
if(className.contains("er")){
return true;
}
return false;
}
}

// return true;加入到容器
//return false;不加入到容器
复制代码
@ComponentScan(value ="com.wzs" ,includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM,value = com.wzs.filter.Myfilter.class)
},useDefaultFilters =false )

 

本例详解:由于指定的包为“com.wzs",故会扫描该包下的所有类,因此该包下的所有类都会被com.wzs.filter.Myfilter.class处理,如果类名包含”er“,则加入到ioc容器,否则不加入到ioc容器

 

## 三、@Scope注解

前景:无论是xml方式加入组件到ioc容器,还是通过注解的方式加入组件到ioc容器,这些组件默认都是单实例的。

1.@Scope注解用在带有@Bean的标签上

2.@Scope注解的取值有:prototype(多实例的)、singleton(单实例的)

配置类的方式给组件赋予单实例或多实例:

复制代码
@Scope("singleton")
@Bean
public Person person(){
return new Person("lisi",18);
}


@Scope("prototype")
@Bean
public Person person(){
return new Person("lisi",18);
}
复制代码

 

xml的方式给组件赋予单实例或多实例:

复制代码
<bean id = "person" class="com.wzs.entity.Person" scope="singleton" >
<property name="name" value="zs"/>
<property name="age" value="18"/>
</bean>

<bean id = "person" class="com.wzs.entity.Person" scope="prototype" >
<property name="name" value="zs"/>
<property name="age" value="18"/>
</bean>
复制代码

 

无论是xml还是配置文件的方式:

​ 单实例的对象创建是在容器启动的时候创建。

​ 多实例的对象创建是在每次获取到该实例的时候创建。

## 四、@Lazy注解

前景:懒加载针对的是单实例的bean,容器启动的时候不创建对象,第一次获取bean时加载.

使用:写在@bean方法之上

配置类的形式:

@Lazy
@Bean
public Person person(){
return new Person("lisi",18);
}

 

xml的形式:

<bean id = "person" class="com.wzs.entity.Person" lazy-init = "true" >
<property name="name" value="zs"/>
<property name="age" value="18"/>
</bean>

 

 

## 五、@Conditional注解

写法:写在@Bean方法或@Configuration类之上。

作用:按照一定的条件,注册指定的bean。其实也类似@ComponentScan中的过滤规则。

使用:

1.创建一个实现了Condition接口的类:

复制代码
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Linux")){//如果当前的操作系统是Linux系统,则将加入到ioc容器中
return true;
}
return false;
}
}
复制代码

 

2.加@Conditional注解

@Conditional(MyCondition.class)
@Bean
public Person person(){
return new Person("lisi",18);
}

 

## 六、@Import注解

@Import注解的作用:导入指定的类到容器中

单个导入类到容器中,默认id是全类名:

@Import(com.wzs.dao.MyDao.class)
@Configuration
public class ApplicationConfig {
}

 

批量导入类到容器中,默认id是全类名:

方式一:

​ 首先实现ImportSelector接口

public class MySelector implements ImportSelector {
//返回的数组封装了加载到ioc容器组件
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
  return new String[]{"com.wzs.service.MyService"};
}
}

 

然后:

@Import(com.wzs.condition.MySelector.class)
@Configuration
public class ApplicationConfig {
}

 

方式二:

首先实现ImportBeanDefinitionRegistrar接口:

public class MyDefiniton implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  RootBeanDefinition bean = new RootBeanDefinition(Person2.class);//注册一个bean
  registry.registerBeanDefinition("person2",bean);//注册到ioc容器中,第一参数指定bean的id,第二个参数指定注册的bean
 }
}

 

然后:

@Import(com.wzs.condition.MyDefiniton.class)
@Configuration
public class ApplicationConfig {
}

===================================================================================================================================

方式三、

导入单个bean到ioc容器中:

首先实现FactoryBean<Person>接口:

复制代码
public class MyFactory implements FactoryBean<Person> {
//返回一个对象并加入到ioc容器中
@Override
public Person getObject() throws Exception {
  return new Person("wzs",22);
}
//类型
@Override
public Class<?> getObjectType() {
  return Person.class;
}
//是否单例
@Override
public boolean isSingleton() {
  return true;
}
}
复制代码
@Configuration
public class ApplicationConfig {
@Bean
public MyFactory myFactory(){
  return new MyFactory();
}
}

 

复制代码
public static void main(String[] args) {
  ApplicationContext ioc = new AnnotationConfigApplicationContext(ApplicationConfig.class);
  Object bean = ioc.getBean("myFactory");
  System.out.println(bean.getClass());//class com.wzs.entity.Person类型

  //如果就是想要工厂对象的话
  Object bean = ioc.getBean("&myFactory");
  System.out.println(bean.getClass()); //class com.wzs.condition.MyFactory
}
复制代码

 

## 七、bean的生命周期

1.bean的生命周期:

​ bean创建 --》 初始化 ---》销毁

2.容器管理bean的生命周期:

我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候调用我们的初始化和销毁方法。

3.具体步骤:

​ 方式一:用@Bean注解,指定初始化和销毁方法

​ 1)自定义初始化和销毁方法

复制代码
public class User {

private int id;
private String name;

public User() {
  System.out.println("无参构造方法");
}

public User(int id, String name) {
  this.id = id;
  this.name = name;
  System.out.println("有参构造方法");
}

public void init(){
  System.out.println("初始化方法");
}

public void destroy(){
  System.out.println("销毁方法");
}
}
复制代码

 

 

2)指定初始化和销毁方法

@Bean(initMethod = "init",destroyMethod = "destroy")
public User user(){
return new User();
}

 

整个调用的过程:构造器 --》初始化 --》容器关闭 --》销毁

 

方式二:实现InitializingBean, DisposableBean接口

1)重写初始化和销毁方法:

复制代码
public class Goods implements InitializingBean, DisposableBean {
  public Goods(){
    System.out.println("构造方法Goods()");
  }

  @Override
  public void destroy() throws Exception {
    System.out.println("销毁方法destroy()");
  }

  @Override
  public void afterPropertiesSet() throws Exception {
    System.out.println("初始化方法afterPropertiesSet()");
  }
}
复制代码

整个调用的过程:构造器 --》初始化 --》容器关闭 --》销毁

方式三:使用jsr250中的注解:

@PostConstruct:在bean创建完成并属性赋值完成后执行的初始化方法。

​ @PreDestroy:在容器销毁bean之前通知进行的清理工作。

 

复制代码
public class Animal {
  public Animal(){
    System.out.println("构造方法Animal()");
  }

  @PostConstruct
  public void init(){
    System.out.println("初始化方法init()");
  }
  @PreDestroy
  public void destroy(){
    System.out.println("销毁方法destroy()");
  }
}
复制代码

 

@Bean
public Animal animal(){
return new Animal();
}

 

整个调用的过程:构造器 --》初始化 --》容器关闭 --》销毁

 

方式四:实现BeanPostProcessor接口,为【所有bean】【初始化方法】【前后】调用的方法

复制代码
//bean的后置处理器
public class MyBeanPostProcessor implements BeanPostProcessor {
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("bean的名字"+beanName+":postProcessBeforeInitialization");
    return bean ;
  }

  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("bean的名字"+beanName+":postProcessAfterInitialization");
    return bean;
  }
}
复制代码

 

复制代码
@Configuration
public class ApplicationConfig {

@Bean
public Animal animal(){
return new Animal();
}
public MyBeanPostProcessor myBeanPostProcessor(){
return new MyBeanPostProcessor();
}

}
复制代码

 

整个调用的过程:构造器 --》postProcessAfterInitialization--》初始化 --》postProcessAfterInitialization--》容器关闭 --》销毁。

即使没有初始化和销毁方法,这些方法也会依次被执行

 

## 八、@Value注解

@Value的用法,给属性赋值:

1.基本数值 2.可以写SpEl表达式:#{} 3.可以写${},取出配置文件的值,但是要结合@PropertySource注解

1)对于第三种方式读取配置文件的值需要先加载配置文件,然后才能读取:

2)@PropertySource(value = {"classpath:/application.properties"}) value指定配置文件的位置;这种方法类似xml中引入外部配置文件<context:property-placeholder location="classpath:application.properties"/>.

3)此外还要说的是@Value方式给bean赋值,是通过Setter方法的方式进行赋值的。

 

## 九、自动装配

### 1.spring规范的@Autowire自动装配:

@Autowire:自动装配 默认首先按照类型自动装配,如果ioc容器中存在多个类型,则按照属性名作为id自动装配;

如果想要装配指定的bean,则【额外】还要加上@Qualifer("id名")进行装配;

默认自动装配一定要装配上的,那么我们可以修改默认值,如果装配不上,则装配null,方法是@Autowire(required=falue)

@Primary指定默认装配首选装配的bean,这样自动装配的时候,首选装配用@Primary修饰的bean;

 

### 2.java规范的@Resouce和@Inject自动装配:

@Resource注解:自动装配默认按照属性名作为id进行自动装配,不支持required=false和@Primary功能;

当然@Resource(“id名”)指定要装配的bean。

 

@Inject注解:使用该注解需要导入javax.inject的jar;自动装配 默认首先按照类型自动装配,如果ioc容器中存在多个类型,则按照属性名作为id自动装配;支持@Primary,但不支持required=false。

 

## 十、针对@Autowire

@Autowire可以标注的位置有:属性、方法、构造器、参数上。

1)标注在类普通方法上:

​ ioc容器创建该bean时,会自动调用用@Autowire标注的方法,并且为该方法上所有参数(引用类型)进行自动装配;

如果在配置类的方式上将bean加入到ioc容器中,如果加入该bean的方法上存在参数,则也会自动装配。

@Bean
public Person person(User user){//User user会自动被装配上
  return new Person();
}

 

 

2)标注在构造器上:

ioc容器创建该bean时,会优先用@Autowird修饰的构造方法创建bean,并为该构造方法的所有参数(引用类型)进行自动装配。

注意:自动装配默认一定要装配上。

## 十一、Aop的使用

1.创建一个被切面切的逻辑处理类

复制代码
package com.wzs.service;

/**
* * Created by wzs on 2020/8/23
**/
public class Calculator {

public int addition(int a,int b){
return a+b;
}
public int substruction(int a,int b){
return a-b;
}
public int multiplication(int a,int b){
return a-b;
}
public int division(int a,int b){
return a-b;
}
}
复制代码

 

2.创建一个切面类

复制代码
package com.wzs.config;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Arrays;

/**
* * Created by wzs on 2020/8/23
**/
@Aspect
public class LogUtils {

@Pointcut("execution(public int com.wzs.service.Calculator.*(..))")
public void poinCut(){}

@Before(value = "poinCut()")
public void logBefore(JoinPoint joinPoint){
  Object[] args = joinPoint.getArgs();
  System.out.println(joinPoint.getSignature().getName()+"方法运行,@before:参数列表:{"+ Arrays.asList(args)+"}");
}

@AfterReturning(value = "poinCut()",returning = "result")
  public void logAfterReturning(JoinPoint joinPoint,Object result){
  System.out.println(joinPoint.getSignature().getName()+"方法运行,@AfterReturning:结果:{"+ result+"}");
}

@AfterThrowing(value = "poinCut()",throwing = "e")
  public void logAfterThrowing(JoinPoint joinPoint,Exception e){
  System.out.println(joinPoint.getSignature().getName()+"方法运行,@AfterReturning:异常原因:{"+ e.getCause()+"}");
}
@After(value = "poinCut()")
public void logAfter(JoinPoint joinPoint){
  System.out.println(joinPoint.getSignature().getName()+"方法运行,@After:");
}
}
复制代码

 

3.将被切和切的类加入到容器,同时开启注解的aop模式@EnableAspectJAutoProxy

复制代码
package com.wzs.config;

import com.wzs.service.Calculator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
* * Created by wzs on 2020/8/23
**/
@EnableAspectJAutoProxy //开启注解形式的aop 类似 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@Configuration
public class AopConfig {
@Bean
public Calculator calculator(){
  return new Calculator();
}
@Bean
public LogUtils logUtils(){
  return new LogUtils();
}
}
复制代码

 

 

## 十一、声明式事务

 

1.写事务,添加@Transactional

复制代码
public class TxService {
@Autowired
JdbcTemplate jdbcTemplate;

@Transactional
public void insert(){
  String sql = "insert into admin(username,password) values(?,?)";
  String substring = UUID.randomUUID().toString().substring(0, 5);
  jdbcTemplate.update(sql,substring,123456);
  System.out.println("插入成功");
  int a = 1/0;
}
}
复制代码

 

2.配置,添加@EnableTransactionManagement

package com.wzs.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
* * Created by wzs on 2020/8/23
**/
@EnableTransactionManagement//开启注解事务,类似xml中的 <tx:annotation-driven transaction-manager = "tm"/>
@Configuration
@Import(com.wzs.service.TxService.class)
public class TxConfig {
@Bean
public DataSource dataSource() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/girls");
dataSource.setUser("root");
dataSource.setPassword("123456");
return dataSource;
}
@Bean
public JdbcTemplate template() throws Exception {
return new JdbcTemplate(dataSource());
}
//配置事务管理器,控制数据源
public PlatformTransactionManager platformTransactionManager() throws Exception {
return new DataSourceTransactionManager(dataSource());
}
}

 

posted on   小吴编  阅读(47)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示