1、@Configuration注解
Bean注解主要用于替代xml配置,同时也是SpringBoot的核心注解
我们用一段代码来演示,如果用注解来替代我们的xml配置
配置文件
<?xml version="1.0" encoding="UTF-8"?> <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"> <bean id="user" class="com.wx.annotation.entity.User"></bean> <bean id="userDao" class="com.wx.annotation.dao.UserDao"></bean> <bean id="userService" class="com.wx.annotation.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean> <context:component-scan base-package="com.wx.annotation"></context:component-scan> </beans>
配置类(@Configuration注解的类等价于applicationContext.xml配置文件)
@Configuration public class AppConfig { }
工厂的转变
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); //使用注解后,需要使用下面的工厂 ApplicationContext ctx = new AnnotationConfigApplicationContext("类路径");
日志的替换(不再使用Log4j)
<!--配置Bean的日志logback--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.logback-extensions</groupId> <artifactId>logback-ext-spring</artifactId> <version>0.1.4</version> </dependency>
logback的配置文件logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 控制台输出 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <!--格式化输出:%d表示⽇期,%thread表示线程名, %-5level:级别从左显示5个字符宽度%msg:⽇志消息,%n是换⾏符--> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT" /> </root> </configuration>
2、@Bean注解
@Configuration替换了xml配置,那在xml中的<bean>标签,也被我们的@Bean注解给替代了
@Bean注解等价于<bean>标签
2.1、对象的创建
- 简单对象:直接new
- 复杂对象:不能直接new,如SqlSessionFactory
所以我们创建简单对象的时候,使用bean注解,一定要是public,返回类型是需要创建对象的类型,方法名等于baen的id值
@Configuration public class AppConfig { @Bean public User user(){ return new User(); } public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); Object user = ctx.getBean("user"); System.out.println(user); } }
测试
那如果我们需要创建复杂对象应该如何创建呢?
@Configuration public class AppConfig { @Bean public User user(){ return new User(); } @Bean public Connection connection(){ Connection conn = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user?useSSL=false","root", "root"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException throwables) { throwables.printStackTrace(); } return conn; } public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); Object connection = ctx.getBean("connection"); System.out.println(connection); } }
测试
对于以前的代码,我们创建复杂对象都是通过FactoryBean接口来进行创建的
public class ConnectionFactoryBean implements FactoryBean<Connection> { public Connection getObject() throws Exception { Connection conn = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user?useSSL=false","root","root"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return conn; } public Class<?> getObjectType() { return Connection.class; } public boolean isSingleton() { return false; } }
那我们现在想要将这个对象通过注解放入到spring中,应该如何操作呢?
@Configuration public class AppConfig { @Bean public User user(){ return new User(); } @Bean public Connection connection(){ Connection conn = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user?useSSL=false","root", "root"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException throwables) { throwables.printStackTrace(); } return conn; } @Bean public Connection connection1() throws Exception { Connection connection = new ConnectionFactoryBean().getObject(); return connection; } public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); Object connection = ctx.getBean("connection1"); System.out.println(connection); } }
测试
可以通过@Bean注解里设置bean的id
@Bean("connection2") public Connection connection1() throws Exception { Connection connection = new ConnectionFactoryBean().getObject(); return connection; }
2.2、控制创建次数
使用@Scope注解,singleton单例,prototype多例
@Bean @Scope("prototype") public User user(){ return new User(); }
2.3、注入
@Bean对象如何注入自定义类型的属性呢
以前配置文件的写法
<bean id="userDao" class="com.wx.annotation.dao.UserDao"></bean> <bean id="userService" class="com.wx.annotation.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean>
使用@Bean注解,注入自定义属性
@Configuration public class AppConfig { @Bean public UserServiceImpl userServiceImpl(){ UserServiceImpl userService = new UserServiceImpl(); userService.setUserDao(new UserDao()); return userService; } public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); UserServiceImpl userService = (UserServiceImpl) ctx.getBean("userServiceImpl"); UserDao userDao = userService.getUserDao(); System.out.println(userDao); } }
注入JDK类型属性
@Configuration @PropertySource("classpath:user.properties") public class AppConfig { @Value("${name}") private String name; @Value("${age}") private Integer age; @Bean @Scope("prototype") public User user(){ User user = new User(); user.setName(name); user.setAge(age); return user; } }
这样我们就通过@Bean实现了解耦
3、@ComponentScan注解
我们之前使用配置文件<context:component-scan base-package="com.wx.annotation"></context:component-scan>,
那么我们@ComponentScan注解就是为了替代我们<context:component-scan>标签,@ComponentScan注解就是为了扫描@Service等注解类
@Configuration @PropertySource("classpath:user.properties") @ComponentScan(basePackages = "com.wx.annotation") public class AppConfig { }
4、优先级
xml配置文件 > @Bean标签 > @Component衍生注解
优先级高的会覆盖优先级低的,主要覆盖的时候,一定要保证id一致。不然得话,容易重复创建bean对象,导致bean冲突