Spring核心技术
DI:依赖注入
IOC:控制反转
AOP:面向切面编程 -- 思想必须掌握
1.Spring配置文件和通过工厂对象创键实例对象
命名无限制,约定有:spring-context.xml,applicationContext.xml,beans.xml
文件结构
bean标签属性讲解
id
Spring-Bean唯一标识
class
Spring-Bean全限定类名
init-method
指定Spring-Bean初始化函数 - 在 class的类里面定义的函数
destroy-method
指定Spring-Bean销毁函数
scope
指定Spring-Bean生命周期 Spring-Bean的生命周期有以下6种:
singleton
单例
prototype
多例
request
请求域
session
会话域
application
上下文域
websocket
会话建立连接时创建,断开连接时销毁
spring-context.xml
<!--配置实例(id:唯一标识, class="需要被创建对象的完全类名"-->
<?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">
<bean id="mc" class="MyClass"/>
</beans>
<!--xmlns:xml namespaces,命名空间,为了避免Spring的beans标签和其他文件中的beans标签重名导致冲突-->
<!--xmlns:xsi : 该文件使用的其他命名空间,名称为xsi,在使用其中的标签时要加入xsi:的前缀.
xmlns冒号后面的命名空间不是固定的,可以变更。xmlns语法为:xmlns:namespace-prefix="namespaceURL"-->
<!--xsi:schemaLocation:属性的值由一个URL引用对组成,两个URL之间以空白符分隔。第一个URL时名称空间的名字
,第二个URL给出模式文档的位置,模式处理器将从这个位置读取模式文档,该模式文档的目标名称空间必须与第一个URL相匹配-->
<!-- 注意:beans标签里面不能添加中文注释,否则报错 -->
<!-- 报错如下:
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 7 in XML document from class path resource [spring-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 7; columnNumber: 13; 2 字节的 UTF-8 序列的字节 2 无效。
-->
pom.xml
<!--Spring-context:spring工厂 常用依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.15</version>
</dependency>
Myclass
public class MyClass {
public void show(){
System.out.println("HelloWorld");
}
}
TestFactory
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestFactory {
/**
* 程序中的对象都交由Spring的ApplicationContext工厂进行创建
*/
public static void main(String[] args) {
// springcontext是spring工厂
// 获取工厂对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
// 通过id创键bean对象
MyClass m = (MyClass) ctx.getBean("mc");
// 调用m对象的方法
m.show();
}
}
2.IoC(Inversion of Control) 控制反转 -- 解决接口和实现类之间的强耦合关系
Inversion of Control: 控制反转
反转了依赖关系的满足方式,由之前的自己创建依赖对象,变为由工厂推送。(变主动为被动,即反转)
解决了具有依赖关系的组件之间的强耦合,使得项目形态更加稳健
在项目中表现:在接口实现类中只定义接口对象,不创建,创建和赋值交给Spring工厂
1.项目中的强耦合问题
public class UserDaoImpl implements UserDao{...}
public class UserServiceImpl implements UserService{
// !!!强耦合了UserDaoImpl,使得UserServiceImpl变得不稳健
private UserDao userDao = new UserDaoImpl();
@Override
public User queryUser(){
return userDao.queryUser();
}
}
2.解决方案
// 不引用任何一个具体的组件(实现类),在需要其他组件的位置预留存取值入口(set/get)
public class UserServiceImpl implements UserService{
// 不在耦合任何DAO实现!!!,消除不稳健因素
private UserDao userDao;
// 为userDao定义set/get,允许userDao属性接受spring赋值
// Getter and Setter
@Override
public User queryUser(){
return userDao.queryUser();
}
}
<bean id="userDAO" class="com.qf.UserDaoImpl"></bean>
<!-- UserServiceImpl组件 -->
<bean id="userService" class="com.qf.UserServiceImpl">
<!-- 由spring为userDAO赋值,值为id="userDAO"的bean -->
<property name="userDAO" ref="userDAO"/>
</bean>
此时,如果需要更换其他UserDao实现类,则UserServiceImpl不用任何改动!
则此时的UserServiceImpl组件变得更加稳健!
3.DI(Dependency Injection)依赖注入【重点】
1. 概念
在Spring创键对象的同时,为其属性赋值,称为依赖注入。
注入分类:
1.Set注入:创建对象时,Spring工厂会通过Set方法为对象的属性赋值。
2.自建类型注入:创键次要bean作为属性,为主要bean赋值
3.构造注入:创建对象时,Spring工厂会通过构造方法为对象的属性赋值.
4.自动注入:不用再配置中指定为哪个属性赋值,及赋什么值,
由Spring自动根据某个"原则",在工厂中找一个bean,为属性注入属性值.
2. Set注入
创建对象时,Spring工厂会通过Set方法为对象的属性赋值。 -- bean对象必须由setter和getter方法
文件结构
2.0 配置文件 - pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qf.edu</groupId>
<artifactId>SpringLearn</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--Spring 工厂 依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.15</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.15</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>*.xml</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>*</include>
<include>**/*</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
2.1 定义目标Bean类型 - User.java
import java.util.*;
public class User {
private Integer id;
private String password;
private String sex;
private Integer age;
private Date bornDate;
private String[] hobbys;
private List<String> names;
private Properties files;
private Map<String,String> countries;
private Set<String> phones;
// getter and setter
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBornDate() {
return bornDate;
}
public void setBornDate(Date bornDate) {
this.bornDate = bornDate;
}
public List<String> getNames() {
return names;
}
public String[] getHobbys() {
return hobbys;
}
public void setNames(List<String> names) {
this.names = names;
}
public Properties getFiles() {
return files;
}
public void setFiles(Properties files) {
this.files = files;
}
public Map<String, String> getCountries() {
return countries;
}
public void setCountries(Map<String, String> countries) {
this.countries = countries;
}
public Set<String> getPhones() {
return phones;
}
public void setPhones(Set<String> phones) {
this.phones = phones;
}
public void setHobbys(String[] hobbys) {
this.hobbys = hobbys;
}
}
2.2 基本类型 + 字符串类型 + 日期类型 + 容器类型 spring-context.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--Set injection-->
<bean id="u1" class="User">
<!-- base field -->
<property name="id" value="1"/>
<property name="password" value="123"/>
<property name="sex" value="male"/>
<property name="age" value="21"/>
<property name="bornDate" value="2000/4/30"/><!-- 注意格式"/" -->
<!--array-->
<property name="hobbys">
<array>
<value>Run</value>
<value>Sleep</value>
</array>
</property>
<!--Set-->
<property name="phones">
<set>
<value>123</value>
<value>234</value>
</set>
</property>
<!--List-->
<property name="names">
<list>
<value>tom</value>
<value>jack</value>
</list>
</property>
<!--Map-->
<property name="countries">
<map>
<entry key="CN" value="China"/>
<entry key="US" value="America"/>
</map>
</property>
<!--Properties-->
<property name="files">
<props>
<prop key="first">One</prop>
<prop key="second">Two</prop>
</props>
</property>
</bean>
</beans>
2.3 测试Set注入 -- TestUser.java
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
// Set注入
public class TestUser {
@Test
public void t(){
// 创键spring-context对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
// 通过工厂反射处user对象
User user = (User) ctx.getBean("u1");
System.out.println(user.getSex());
System.out.println(user.getBornDate());
// 字符串array
for (String hobby : user.getHobbys()) {
System.out.print(hobby+" ");
}
// map
for (String value : user.getCountries().values()) {
System.out.print(value+" ");
}
}
}
3.自建类型注入
把次要bean作为属性,为主要bean赋值
3.1 spring-context.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--definition type injection -->
<!-- 次要bean ,作为主题的属性注入 Address和AddressDemo都和resource目录同一级别 -->
<bean id="addr" class="Address">
<property name="position" value="北京市海淀区"/>
<property name="zipCode" value="100001"/>
</bean>
<!-- 主要bean ,操作的主体-->
<bean id="ad" class="AddressDemo">
<property name="address" ref="addr"/>
</bean>
</beans>
3.2 pom.xml同上
3.3 Address.java
public class Address {
private String position;
private String zipCode;
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
}
3.4 AddressDemo.java
public class AddressDemo {
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
3.4 测试
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentTest {
@Test
public void t(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
Student st = (Student) ctx.getBean("s");
st.show();
}
}
4.构造注入
3.构造注入:创建对象时,Spring工厂会通过构造方法为对象的属性赋值.
4.1 pom.xml同上
4.2 Bean对象 - Student.java
public class Student {
private Integer id;
private String name;
private String sex;
private Integer age;
// Constructors
public Student(Integer id, String name, String sex, Integer age) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}
public void show(){
System.out.println("id:"+id);
System.out.println("name:"+name);
System.out.println("sex:"+sex);
System.out.println("age:"+age);
}
}
4.3 spring-context.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- constuctor injection -->
<bean id="s" class="Student">
<!-- name == index -->
<constructor-arg index="0" value="1234"/>
<constructor-arg index="1" value="tom"/>
<constructor-arg index="2" value="male"/>
<constructor-arg index="3" value="20"/>
</bean>
</beans>
4.4 测试 StudentTest
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentTest {
@Test
public void t(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
Student st = (Student) ctx.getBean("s");
st.show();
}
}
5.自动注入【了解】
不用再配置中指定为哪个属性赋值,及赋什么值。
有spring自动根据某个“原则”,在工厂中查找一个bean,为属性注入属性值
4.Bean细节
1.控制简单对象的单例、多例模式
sprint-context.xml
<bean scope="singleton|prototype"/>
<!--
singleton(默认):每次调用工厂,得到的都是同一个对象
prototype:每次调用工厂,都会创建新的对象
-->
<bean id="mc" class="MyClass" scope="singleton"/>
- 注意:需要根据场景决定对象的单例、多例模式
- 可以共用:Servie,DAO,SqlSessionFactory(或者所有工厂)
- 不可共用:Connection,SqlSession,ShoppingCart
5.Spring工厂
1.饿汉式创键优势
工厂创建后,会将Spring配置文件中的所有对象都创建完成(饿汉式).
提高程序运行效率。避免多次IO,减少对象创建时间。(类似于连接池)
2.生命周期方法
- 自定义初始化方法:添加"init-method"属性,Spring则会在创建对象之后,调用此方法.
- 自定义销毁方法:添加"destory-method"属性,Spring则会在销毁对象之前,调用此方法
- 销毁:工厂的close()方法被调用之后,Spring会毁掉所有已创键的单例对象
- 分类:Singleton对象由Spring容器销毁、Prototype对象由JVM销毁
3.生命周期注解
初始化注解:@PostConstruct
销毁注解:@PreDestory
4.生命周期阶段
单例Bean:singleton
随工厂启动 创键=> 构造方法 => set方法(注入值) => init(初始化) => 构建完成 => 随工厂关闭销毁
多例Bean:prototype
被使用 创键 => 构造方法 => set方法(注入值) => init(初始化) => 构建完成 =>JVM垃圾回收销毁
6.AOP(面向切面编程) - Aspect Oriented Programming【思想重点,在spring和mvc种一般不用,但必须会思想】
AOP,即面向切面编程,利用一种称为"横切"的技术,抛开封装的对象内部,并将那些影响了多个磊的公共行为封装到一个可重用模块,并将其名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,缺位业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
0.实现原理
使用动态代理技术
- 基于接口的JDK官方的动态代理(优先使用)
- 基于子类的第三方的cglib的动态代理
- 基于Spring的动态代理ProxyFactory
1.AOP开发术语
- 连接点(Joinpoint):连接点是程序类中客观存在的方法,可被Spring拦截并切入内容。
- 切入点(Pointcut):被Spring切入连接点。
- 通知、增强(Advice):可以为切入点添加额外功能,分为:前置通知,后置通知,异常通知,环绕通知等。
- 目标对象:代理的目标对象
- 引介(Introduction):一种特殊的增强,可以在运行期为动态类添加Field和Method。
- 织入(Weaving):把通知应用到具体的类,进而创键新的代理类的过程。
- 代理(Proxy):被AOP织入通知后,产生的结果类。
- 切面(Aspect):由切点和通知组成,将横切逻辑织入切面所指定的连接点中。
2.作用
Spring的AOP编程即是通过动态代理类为原始类的方法添加辅助功能。
在程序运行期间,不修改源码对已有方法进行增强
3.环境搭建
引入AOP相关依赖
<!--spring aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.15</version>
</dependency>
spring-context.xml引入AOP命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" <!--spring context -->
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
<!--spring context -->
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
<!--spring context -->
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
4.开发流程
定义原始类
UserService.java
package com.qf.aaron.aop.basic;
// 原始类
public interface UserService {
public void save();
}
UserServiceImpl.java
package com.qf.aaron.aop.basic;
// 原始类
public class UserServiceImpl implements UserService{
public void save() {
System.out.println("save method executed...");
}
}
定义通知类(添加额外功能)
package com.qf.aaron.aop.basic;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyAdvice implements MethodBeforeAdvice {
// 实现前置通知接口
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before advice executed");
}
}
定义bean标签 - spring-context.xml
<!-- 原始对象 -->
<bean id="us" class="com.qf.aaron.aop.basic.UserServiceImpl"/>
<!-- 辅助对象 -->
<bean id="myAdvice" class="com.qf.aaron.aop.basic.MyAdvice"/>
定义切入点(PointCut)
形成切面
<aop:config>
<!-- 切点 -->
<aop:pointcut id="myPonitCut" expression="execution(* save())"/>
</aop:config>
<aop:config>
<!-- 组装切面 -->
<aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut"/>
</aop:config>
5.通知类【可选】
定义通知类,达到通知效果 -- 神魔时候做什莫
前置通知:MethodBeforeAdvice
后置通知:AfterAdvice
后置通知:AfterReturningAdvice //有异常不执行,方法会因异常而结束,无返回值
异常通知:ThrowsAdvice
环绕通知:MethodInterceptor
6.通配切入点 - 切点表达式
根据表达式通配切入点
execution(
[访问修饰符]
[返回类型]
[全限定类名 . ]
访问名
(参数类型 | ".." , ... )
[ throws 异常类型 ]
)
<!-- 匹配参数 -->
<aop:pointcut id="myPointCut" expression="execution(* *(com.qf.aaron.aop.basic.User))"/>
<!-- 匹配方法名(无参) -->
<aop:pointcut id="myPointCut" expression="execution(* save())"/>
<!-- 匹配方法名(任意参数) -->
<aop:pointcut id="myPointCut" expression="execution(* save(String s))"
<!-- 匹配返回值类型 -->
<aop:pointcut id="myPointCut" expression="execution(com.qf.aaron.aop.basic.User *(参数))"/>
<!-- 匹配类名 -->
<aop:pointcut id="myPointCut" expression="execution(* com.qf.aaron.aop.basic.UserServiceImpl.*(参数))"/>
<!-- 匹配包名 -->
<aop:pointcut id="myPointCut" expression="execution(* com.qf.aaron.aop.basic.*.*(参数))"/>
<!-- 匹配包名、以及子包名 -->
<aop:pointcut id="myPointCut" expression="execution(* com.qf.aaron.aop..*.*(参数))"/>
7.JDK和CGLIB选择
- spring底层,包含了jdk代理和cglib代理两种动态代理生成机制
- 基本规则是:目标业务类如果有接口则用JDK代理,没有接口则用CGLib代理
class DefaultAopProxyFactory{
// 该方法中明确定义了 JDK代理和CGLib代理的选取规则
// 基本规则是:目标业务中如果有接口则用JDK代理,没有接口则用CGLib代理
public AopProxy createAopProxy(){
...
}
}
8.后处理器
- spring中定义了很多后处理器;
- 每个bean对象在创键完成之前,都会有一个后处理过程,即在加工,对bean做出相关改变和调整;
- spring-AOP中,就有一个专门的后处理器,负责通过原始业务组件(Service),再加工得到一个代理组件。
后处理器的定义 - MyBeanPostProcessor.java
package com.qf.aaron.aop.basic;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* 定义在bean后处理器
* 作用:在bean的创键之后,进行再加工
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* 在bean的init方法之前执行
* @param bean 原始的bean对象
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessBeforeInitialization(Object bean,String beanName) throws BeansException{
System.out.println("后处理器 在init之前执行"+bean.getClass());
return bean;
}
/**
* 在bean的init方法之后执行
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessAfterInitialization(Object bean,String beanName) throws BeansException{
System.out.println("后处理器 在init之后执行~~~"+bean.getClass());
return bean;// 此处返回的是getBean()最终的结果
}
}
配置后处理器
<!-- 配置后处理器,将对工厂中所有的bean生命周期进行干预 -->
<bean class="com.tx.beanpostprocessor.MyBeanPostProcessor"/>
bean生命周期
构造 => 注入属性 满足依赖 => 后处理器前置过程 => 初始化 => 后处理器后置过程 => 返回 => 销毁
7. 注解开发【重点】
1.声明bean
用于替换自建类型的 标签;可以更快速的声明bean
@Service 业务类专用
@Repository dao实现类专用
@Controller web层专用
@Component :IoC注解,用于描述一个类,当Spring容器扫描到此类之后,将此类的实例放到Spring容器中,默认情况下,容器bean的id为类名的大驼峰-》小驼峰
如果不想默认,显示指定为@Component("userService")
@Scope 用户控制bean的创键模式
@Service注解 -- 可以带参数,也可以不带
// @Service说明 此类是一个业务类,需要将此类纳入工厂
// @Service默认beanId 是 首字母小写的类名 eg:"userServiceImpl"
// @Service("userService") 自定义beanId为"userService"
@Service // 声明bean,且id="userServiceImpl"
@Scope("singleton") // 声明bean对象创键模式,默认单例模式;@Scope("prototype")为设置多例模式
public class UserServiceImpl implements UserService{
...
}
@Service
@Scope
== spring-context.xml中的<bean id=首字母小写类名 class=xx scope=xx/>
2.注入(DI)
用于完成bean中属性值的注入
- @Autowired 基于类型的自动注入
- @Resource 基于名称自动注入
- @Qualifier("userDao") ,限定要注入的bean的id,和@Autowired配合使用
- @Value 注入简单类型数据(jdk8种+String)
@Service
public class UserServiceImpl implements UserService{
@Autowired //注入类型为UserDAO的bean
@Qualifier("userDAO2") // 如果有多个类型为UserDao的bean,可以用此注解从中挑选一个
private UserDAO userDAO;
@Resource("userDAO3")
private UserDAO userDAO1;
@Value("100") // 注入数字
private Integer id;
}
3.事务控制
用于控制事务切入
- @Transactional
- 工厂配置中的<tx:advice...和<aop:config...可以省略!!
4.注解所需要的配置 spring-context.xml
<!-- 告知sping,哪些包有被注解的类、方法、属性 -->
<!-- <context:component-scan base-package=""></context:component-scan> -->
<context:component-scan base-package="com.tx"></context:component-scan>
<!-- 告知spring,@Transcational在定制事务时,基于txManager=DataSourceTransactionManager -->
<tx:annotation-driven transaction-manager="txManager"/>
5.AOP开发 -- 使用注解
使用注解
AOP使用注解配置
<!-- 添加配置如下,启用aop注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
6. 生命周期注解
@PostConstruct:生命周期注解,在此SpringBean实例化之后,执行此注解描述的方法
@PreDestory:生命周期注解,在此SpingBean销毁之前,执行此注解所描述的方法