1 实例化bean的三种方法
①使用构造函数实例化
ApplicationContext Context = new ClassPathXmlApplicationContext("SpringIoc.xml");
UserDao bean = (UserDao) Context.getBean("subsystemA-dataSource");
<bean id="userDao" name="userDao" class="com.cql.Dao.UserDao">
<!-- collaborators and configuration for this bean go here -->
</bean>
<alias name="userDao" alias="subsystemA-dataSource"/>
public class UserService {
private static final UserService userService = new UserService();
private UserDao userDao;
private AddressDao addressDao;
private UserService(){
}
public UserService(UserDao userDao, AddressDao addressDao) {
this.userDao = userDao;
this.addressDao = addressDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setAddressDao(AddressDao addressDao) {
this.addressDao = addressDao;
}
public static UserService createUserService(){
return userService;
}
public UserDao USCreateUserDao(){
return new UserDao();
}
}
②使用静态工厂方法实例化
ApplicationContext Context1 = new ClassPathXmlApplicationContext("SpringIoc.xml");
UserService userService = (UserService) Context.getBean("service");
UserDao userdao = userService.USCreateUserDao();
<bean id="userService" name="service" class="com.cql.Service.UserService" factory-method="createUserService">
<!-- collaborators and configuration for this bean go here -->
</bean>
③使用实例工厂方法实例化
ApplicationContext Context = new ClassPathXmlApplicationContext("SpringIoc.xml");
UserDao userDao = (UserDao) Context.getBean("userDao_in_Service");
<bean id="userService" name="service" class="com.cql.Service.UserService" factory-method="createUserService">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="userDao_1" name="userDao_in_Service" factory-bean="service" factory-method="USCreateUserDao">
<!-- collaborators and configuration for this bean go here -->
</bean>
2 IoC容器
2.1 依赖注入
DI主要有以下两种方式:①Constructor-based依赖注入,基于构造器的依赖注入,本质上是使用构造器给成员变量赋值。②Setter-based依赖注入,基于setter方法的依赖注入,本质上是使用set方法给成员变量赋值。
①构造器注入
ApplicationContext Context = new ClassPathXmlApplicationContext("SpringIoc.xml");
UserService userService = (UserService) Context.getBean("userServiceC");
userService.PrintConstruct();
<!-- 利用bean通过构造函数构造对象,构造器注入 -->
<!-- constructor-arg中有index属性,用于指明UserService中构造器的参数顺序,有name属性,用于指明构造器的参数名字,避免歧义 -->
<bean name="userServiceC" class="com.cql.Service.UserService">
<constructor-arg ref="userDaoSC"/>
<constructor-arg ref="addressDaoSC"/>
</bean>
<bean id="userDaoSC" class="com.cql.Dao.UserDao">
</bean>
<bean id="addressDaoSC" class="com.cql.Dao.AddressDao">
</bean>
②setter注入
ApplicationContext Context = new ClassPathXmlApplicationContext("SpringIoc.xml");
UserService userService = (UserService) Context.getBean("userServiceS");
userService.PrintConstruct();
<!-- 利用bean通过setter构造对象,setter注入 -->
<bean name="userServiceS" class="com.cql.Service.UserService">
<property name="userDao" ref="userDaoSS"/>
<property name="addressDao" ref="addressDaoSS"/>
</bean>
<bean id="userDaoSS" class="com.cql.Dao.UserDao">
</bean>
<bean id="addressDaoSS" class="com.cql.Dao.AddressDao">
</bean>
2.2 自动装配
Spring容器可以自动装配引用数据类型---协作bean之间的关系。自动装配可以显著减少指定属性或构造函数参数的需要,还可以随着对象的发展更新配置。bean的autowire属性,有no、byName、byType和constructor,在需要自动装配引用数据类型的bean中添加该属性,便可实现自动装配。
2.3 bean的生命周期
①创建回调和销毁回调--实现接口,重写方法。
public class People implements InitializingBean, DisposableBean {
}
②不推荐实现接口,这样会与Spring藕合在一起,而是使用bean的两个属性,在people类中实现init和cleanup方法。
<bean id="people" class="com.cql.entity.People" init-method="init">
</bean>
<bean id="people" class="com.cql.entity.People" destroy-method="cleanup">
</bean>
③也可以使用注解来操作。
<!--依赖-->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<!--beans修改-->
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<!--开启注解-->
</beans>
//java代码中的函数添加注解
@PostConstruct
public void initC(){
System.out.println("CCInit!!!");
}
@PreDestroy
public void destroyC(){
System.out.println("CCDestroy!!!");
}
④在beans中定义全局默认的init和destroy方法,只要类中声明了同名方法,便可实现相应功能。
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd" default-init-method="init" default-destroy-method="destroy">
<!--开启注解-->
<context:annotation-config/>
</beans>
2.4 classpath扫描和组件管理
通过扫描类的注解来进行容器填充,而不是通过xml文件的读取。@Component
是任何spring管理组件的通用注解,只要在类上添加了该注解,便是定义了一个bean。@Repository
、@Service
和@Controller
是比@Component
用于更具体用例的注解(分别代表持久层,业务层和控制层),这些注解对后期对特定bean进行批量处理时是有帮助。
【常用方法】
//在所有需要注入的类上添加注解@Component(通用注解)/@Repository(持久层)/@Service(业务层)/@Controller(控制层)
//指定一个包名,自动扫描会检测这个包"org.example"及其子包下的所有类信息。
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
}
<?xml version="1.0" encoding="UTF-8"?>
<beans
<context:annotation-config/>
<bean name="appConfig" class="com.cql.AppConfig"/>
</beans>
ApplicationContext Context = new ClassPathXmlApplicationContext("AnnotationIoC.xml");
Pet pet = Context.getBean(Pet.class);
System.out.println(pet);
2.5 环境抽象
public void DataSourceConfigTest(){
//1.创建容器
AnnotationConfigApplicationContext aCAContext = new AnnotationConfigApplicationContext();
//2.激活环境
aCAContext.getEnvironment().setActiveProfiles("pro");
//3.打包
aCAContext.scan("spring.dataSource");
//4.刷新
aCAContext.refresh();
DataSource bean = aCAContext.getBean(DataSource.class);
System.out.println(bean);
}
2.6 事件监听机制
【实现监听事件】的两种方法:
①实现ApplicationListener接口,重写onApplicationEvent()方法。
@Component
public class EmailListener implements ApplicationListener<OrderEvent> {
@Override
public void onApplicationEvent(OrderEvent event) {
System.out.println("Email监听到了");
}
}
②利用@EventListener注解来监听。
@Component
public class MsgListenerAnno {
@EventListener
public void msgListenerAnnoWay(OrderEvent event){
System.out.println("发送消息到手机...");
}
}
【发布自定义事件】--分两步:
①OrderEvent实体类继承ApplicationEvent类。
public class OrderEvent extends ApplicationEvent {
/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public OrderEvent(Object source) {
super(source);
}
}
②实现ApplicationEventPublisherAware接口
public class OrderService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void SendMsg(Order orderService){
applicationEventPublisher.publishEvent(orderService);
}
}
public void ServiceTest(){
ApplicationContext Context = new AnnotationConfigApplicationContext(AppConfig.class);
OrderService orderService = new OrderService();
orderService.setApplicationEventPublisher(Context);
orderService.SendMsg(new OrderEvent(new Order(1, "鸡腿")));
}
3 AOP
要在Spring配置中使用@AspectJ注解,您需要启用Spring支持,以便基于@AspectJ注解配置Spring AOP,如果Spring确定一个bean被一个或多个切面通知,它将自动为该bean生成一个代理,以拦截方法调用,并确保通知在需要时运行。
@Component
@ComponentScan(basePackages = "com.cql")
@EnableAspectJAutoProxy
public class AppConfig {
}
@Aspect
@Component
public class MyAspectJAnno {
/**
* 声明一个切点,pointCut()指向execution中定义的com.cql类下的所有public方法
*/
@Pointcut("execution(public * com.cql..*(..))")
private void pointCut(){
}
@DeclareParents(value="com.cql.service.Impl.OrderService",defaultImpl= MeuService.class)
public static IMeuService meuServiceWay;
@Before("pointCut()")
private void beforeAdvice(JoinPoint jp){
System.out.println("this is before Advice 1");
MethodSignature signature = (MethodSignature)jp.getSignature();
Method method = signature.getMethod();
try {
method.invoke(jp.getTarget(), jp.getArgs());
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
System.out.println("this is before Advice 2");
}
@AfterThrowing(value = "execution(public * com.cql..*(..))", throwing="ex")
public void afterThrowingAdvice(ArithmeticException ex) {
System.out.println("this is afterThrowing Advice");
System.out.println("========================>" + ex);
}
@AfterReturning("pointCut()")
private void afterReturningAdvice(){
System.out.println("this is afterReturningAdvice");
}
@After("pointCut()")
private void afterAdvice(){
System.out.println("this is after Advice");
}
/**
* around可用于事务的增强
* @param pjp
* @return
*/
@Around("pointCut()")
private Object aroundAdvice(ProceedingJoinPoint pjp){
System.out.println("this aroundAdvice before");
// 这里是真正bean的方法调用的地方
try {
pjp.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}
System.out.println("this aroundAdvice after");
return null;
}
}
4 事务
4.1 编程式事务
编程式事务比较少用,使用【TransactionTemplate】绝对会将您与Spring的事务基础设施和api耦合在一起。
Spring Framework提供了两种编程式事务管理的方法:
①使用TransactionTemplate
。
public void transferMoney3(String from, String to, Integer money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// 转账其实是两个语句
String moneyFrom = "update spring_tx set salary = salary - ? where name = ? ";
String moneyTo = "update spring_tx set salary = salary + ? where name = ? ";
// 从转账的人处扣钱
jdbcTemplate.update(moneyFrom, money, from);
jdbcTemplate.update(moneyTo, money, to);
}
});
}
②使用 TransactionManager
。
public void transferMoney2(String from, String to, Integer money) {
// 默认的事务配置
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
// 使用事务管理器进行事务管理
TransactionStatus transaction = transactionManager.getTransaction(definition);
// 转账其实是两个语句
String moneyFrom = "update spring_tx set salary = salary - ? where name = ? ";
String moneyTo = "update spring_tx set salary = salary + ? where name = ? ";
try{
// 从转账的人处扣钱
jdbcTemplate.update(moneyFrom, money, from);
// int i = 1/0;
jdbcTemplate.update(moneyTo, money, to);
} catch (RuntimeException e){
e.printStackTrace();
transactionManager.rollback(transaction);
}
transactionManager.commit(transaction);
}
【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:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="jdbc.properties"/>
<context:component-scan base-package="com.cql"/>
<!-- 注入事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- JDBC样板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="dataSourceTransactionManager"/>
</bean>
<!-- 数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.URL}"/>
<property name="driverClassName" value="${jdbc.driverName}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
4.2 声明式事务
大多数Spring框架用户选择声明式事务管理。 该选项对应用程序代码的影响最小,因此最符合非侵入式轻量级容器的理想。
Spring框架的声明式事务通过AOP代理进行实现,事务的通知是由AOP元数据与事务性元数据的结合产生了一个AOP代理,该代理使用【TransactionInterceptor】结合适当的【TransactionManager】实现来驱动方法调用的事务。
Spring Framework的【TransactionInterceptor】为命令式和响应式编程模型提供了事务管理。 拦截器通过检查方法返回类型来检测所需的事务管理风格。 事务管理风格会影响需要哪个事务管理器。 命令式事务需要【PlatformTransactionManager】,而响应式事务使用【ReactiveTransactionManager 】实现。
【@Transactional 】通常用于【PlatformTransactionManager 】管理的【线程绑定事务】,将事务暴露给当前执行线程中的所有数据访问操作。(注意:这不会传播到方法中新启动的线程)。
【Xml形式】
【自定义事务通知】
<aop:config>
<aop:pointcut id="point" expression="execution(* com.cql.service..*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
</aop:config>
<bean id="txAdvice" class="com.cql.AOP.TXAdvice">
<property name="transactionManager" ref="dataSourceTransactionManager"/>
</bean>
public class TXAdvice implements MethodInterceptor {
private PlatformTransactionManager transactionManager;
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
// 默认的事务配置
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
// 使用事务管理器进行事务管理
TransactionStatus transaction = transactionManager.getTransaction(definition);
Object invoke = null;
try{
invoke = methodInvocation.getMethod().invoke(methodInvocation.getThis(), methodInvocation.getArguments());
}catch (RuntimeException e){
e.printStackTrace();
transactionManager.rollback(transaction);
}
transactionManager.commit(transaction);
return invoke;
}
}
【官方事务通知】
<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the FooService interface -->
<aop:config>
<aop:pointcut id="point" expression="within(com.cql.service..*)"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
</aop:config>
【统一事务执行代码】
public void transferMoney1(String from, String to, Integer money) {
// 转账其实是两个语句
String moneyFrom = "update spring_tx set salary = salary - ? where name = ? ";
String moneyTo = "update spring_tx set salary = salary + ? where name = ? ";
// 从转账的人处扣钱
jdbcTemplate.update(moneyFrom, money, from);
jdbcTemplate.update(moneyTo, money, to);
}
【注解形式】
@Transactional
@Transactional
public void transferMoney1(String from, String to, Integer money) {
// 转账其实是两个语句
String moneyFrom = "update spring_tx set salary = salary - ? where name = ? ";
String moneyTo = "update spring_tx set salary = salary + ? where name = ? ";
// 从转账的人处扣钱
jdbcTemplate.update(moneyFrom, money, from);
int i =1/0;
jdbcTemplate.update(moneyTo, money, to);
}
<!--在xml中开启事务注解-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
5 依赖配置总结
<!--Spring核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<!--Spring开启注解依赖-->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<!--切面编程所需依赖-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
</dependency>
<!--Spring事务依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>6.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.0.6</version>
</dependency>
6 配置文件总结
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<!--开启p命名空间-->
xmlns:p="http://www.springframework.org/schema/p"
<!--开启c命名空间-->
xmlns:c="http://www.springframework.org/schema/c"
<!--开启事务-->
xmlns:tx="http://www.springframework.org/schema/tx"
<!--开启aop-->
xmlns:aop="http://www.springframework.org/schema/aop"
<!--开启注解-->
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
</beans>
通过配置文件注入bean
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1.使用构造函数实例化-->
<bean id="userDao" name="userDao" class="com.cql.Dao.UserDao">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!--起别名-->
<alias name="userDao" alias="subsystemA-dataSource"/>
<bean id="userService" name="service" class="com.cql.Service.UserService" factory-method="createUserService">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="userDao_1" name="userDao_in_Service" factory-bean="service" factory-method="USCreateUserDao">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
【AspectJ代理】
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:config>
<!-- 定义切面 -->
<aop:aspect ref="aopXml">
<!-- 定义切点 -->
<aop:pointcut id="point" expression="execution(* com.cql.service.Impl.OrderService.order(..))"/>
<!-- pointcut="execution(* com.cql..*(..))" -->
<aop:before method="beforeAdvice" pointcut-ref="point" />
<aop:after-throwing method="afterThrowingAdvice" throwing="ex" pointcut-ref="point"/>
<aop:after-returning method="afterReturningAdvice" pointcut-ref="point"/>
<aop:after method="afterAdvice" pointcut-ref="point"/>
<!-- <aop:around method="aroundAdvice" pointcut="execution(* com.cql..*()) and args(name)"/>-->
</aop:aspect>
</aop:config>
<bean id="aopXml" class="com.cql.aspectJ.MyAspectJXml"/>
<bean id="orderService" class="com.cql.service.Impl.OrderService"/>
<bean id="userService" class="com.cql.service.Impl.UserService"/>
<bean id="meuService" class="com.cql.service.Impl.MeuService"/>
</beans>
7 注解配置总结
//bean添加初始化回调和销毁回调,实现方法的增强操作,在实体类中实现下面方法并使用注解
@PostConstruct
public void init(){
System.out.println("init!!!");
}
@PreDestroy
public void destroy(){
System.out.println("destroy!!!");
}
//设置required=false,bean中没有配置,则忽略,实现bean中引用数据类型的自动配置
①@Autowired(required = false)
该注解用于实体类的属性字段和setter方法上,实现以注解的方式自动按【类型】注入其他bean。@Autowired添加在setter方法上,表示以setter注入,添加在构造器上,表示以构造器注入。
②@Resource
@Resource(name = "xxx"),与@Autowired作用类似,该注解用于实体类的属性字段和setter方法上,实现以注解的方式自动按【名字】注入其他bean。“xxx”代表容器中bean的名字。若不配name属性,则在容器中寻找名为成员变量名称的bean,将其注入;若配了,选择与bean的name一致的将其注入,若没有找到,则按照类型进行匹配。
//微调基于注解的自动装配,当容器中有多个继承同一个类的参数,但类中只有一个成员变量,可以在xml中使用注解指定首要的参数
@Primary、@Qualifier
③@Primary
由于@Autowired按类型自动装配可能会导致多个【候选者】,因此通常需要对选择过程进行更多的控制。 实现这一点的一种方法是使用Spring的【@Primary 】注解。【@Primary】表示当多个bean可以作为一个依赖项的候选bean时,应该优先考虑某个特定bean。 如果在候选bean中恰好存在一个主要的bean,那么它将成为自动连接的值。
④@Qualifier
该注解有name属性,@Qualifier("xxx"),可以指定自动注入的bean的名称,通过惟一的【名称标识】选择选取一个特定的bean进行注入。
//向Spring IoC容器注册bean的注解
① @Bean--用于在配置类中注入自定义或jar包中的对象。该注解定义在配置类中,用于指示一个方法,该方法负责【实例化、配置和初始化】一个由Spring IoC容器管理的新对象。
@Bean中有initMethod和destroyMethod属性,指定该bean的初始化回调和销毁回调的函数。
以下注解用于向容器注入自定义的对象。
② @Component(通用注解)/@Repository(持久层)/@Service(业务层)/@Controller(控制层)
//定义一个bean的配置类
@Configuration
@ComponentScan(basePackages = "org.example")
@Import({xxx.class, xxx.class, ...})
public class AppConfig {
}
<?xml version="1.0" encoding="UTF-8"?>
<beans
<context:annotation-config/>
<bean name="appConfig" class="com.cql.AppConfig"/>
</beans>
在Spring XML文件中使用@Import元素来实现模块化配置一样,@Import注解允许一个【配置类】加载另一个【配置类】。
如果要引入多个类,可通过以下方式,AppConfig中只需要@Import(ConfigSelector.class)
即可。
public class ConfigSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.ydlclass.A","com.ydlclass.B"};
}
}
//定义在@Bean等注册bean的注解下,用于指定bean的作用范围
@Scope
//描述作用的注解,只起提示作用
@Description("Provides a basic example of a bean")
配置类使用配置文件的参数值
@Configuration
//读取xml
@ImportResource("classpath:/com/acme/properties-config.xml")
//读取yml和properties
@PropertySource("classpath:com/myco/app.properties")
public class AppConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
return new DriverManagerDataSource(url, username, password);
}
}
<beans>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
</beans>
【环境抽象】
@Profile
该注解是方法级注解,@Profile("xxx"),指定一个数据源bean所使用的参数配置
【事件监听】
@EventListener
@EventListener是方法级注解,用于事件监听
【AOP代理】
@Component
@ComponentScan(basePackages = "com.cql")
//开启AspectJ事务自动代理
@EnableAspectJAutoProxy
public class AppConfig {
}
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--@EnableAspectJAutoProxy注解与下面的xml配置功能一致-->
<!-- bean definitions here -->
<aop:aspectj-autoproxy/>
</beans>
@Aspect //定义一个切面类
@Component
public class MyAspectJAnno {
/**
* 声明一个切点,pointCut()指向execution中定义的com.cql类下的所有public方法
*/
@Pointcut("execution(public * com.cql..*(..))")
private void pointCut(){
}
/**
* 让代理对象实现新的接口,该接口的方法会在最后自动执行
*/
@DeclareParents(value="com.cql.service.Impl.OrderService",defaultImpl= MeuService.class)
public static IMeuService meuServiceWay;
@Before("pointCut()")
private void beforeAdvice(JoinPoint jp){
}
@AfterThrowing(value = "execution(public * com.cql..*(..))", throwing="ex")
public void afterThrowingAdvice(ArithmeticException ex) {
}
@AfterReturning("pointCut()")
private void afterReturningAdvice(){
}
@After("pointCut()")
private void afterAdvice(){
}
/**
* around可用于事务的增强
* @param pjp
* @return
*/
@Around("pointCut()")
private Object aroundAdvice(ProceedingJoinPoint pjp){
}
}
【事务】
@Transactional
public void transferMoney1(String from, String to, Integer money) {
// 转账其实是两个语句
String moneyFrom = "update spring_tx set salary = salary - ? where name = ? ";
String moneyTo = "update spring_tx set salary = salary + ? where name = ? ";
// 从转账的人处扣钱
jdbcTemplate.update(moneyFrom, money, from);
int i =1/0;
jdbcTemplate.update(moneyTo, money, to);
}
<!--在xml中开启事务注解-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
【纯注解事务】
@Configuration
@ComponentScan(basePackages = "com.cql")
@EnableTransactionManagement //开启事务
@PropertySource("classpath:jdbc.properties")
public class AppConfig {
}