前置知识:JSP&Servlet
学习视频:https://www.bilibili.com/video/BV1WE411d7Dv?spm_id_from=333.999.0.0
IoC:控制反转
IoC的理解:IoC思想,IoC怎么创建对象,IoC是Spring的核心
依赖注入三种方式:构造器、set方法、第三方
Bean的作用域:2+4
单例与原型
request,session,appication=websocket
Bean属性的自动装配:四种
xml显示配置
隐式自动配置(ByName——参数名,ByType——参数类型)
注解
实现配置类:不用xml配置,把配置项作为类属性
Bean的生命周期
代理模式
AOP
解决企业级应用开发的复杂性创建,简化开发
轻量级控制反转(IOC)和面向切面编程(AOP)的容器框架
文档地址
各版本文档
下载地址
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.3version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.3version>
dependency>
弊端:发展太久,配置十分繁琐
以JDBC连接数据库为例
UserDao接口
public interface UserDao {
public void getUser();
}
UserDaoImpl实现类
//UserDaoImpl.class
public class UserDaoImpl implements UserDao{
public void getUser(){
System.out.println("获取用户数据");
}
}
//UserDaoMysqlImpl
public class UserDaoMysqlImpl implements UserDao{
public void getUser(){
System.out.println("MySql获取用户数据");
}
}
//UserDaoOracleImpl
public class UserDaoOracleImpl implements UserDao{
public void getUser(){
System.out.println("Oracle实现获取用户数据");
}
}
UserService业务接口
public interface UserService {
public void getUser();
}
UserServicelmpl业务实现类
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoMysqlImpl();
// = new UserDaoOracleImpl();
// = new UserDaoImpl();
public void getUser(){
userDao.getUser();
}
}
MyTest
public class MyTest {
public static void main(String[] args) {
//用户实际调用的是业务层
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
UserDao接口
public interface UserDao {
public void getUser();
}
UserDaoImpl实现类
//UserDaoImpl.class
public class UserDaoImpl implements UserDao{
public void getUser(){
System.out.println("获取用户数据");
}
}
//UserDaoMysqlImpl
public class UserDaoMysqlImpl implements UserDao{
public void getUser(){
System.out.println("MySql获取用户数据");
}
}
//UserDaoOracleImpl
public class UserDaoOracleImpl implements UserDao{
public void getUser(){
System.out.println("Oracle实现获取用户数据");
}
}
UserService业务接口
public interface UserService {
public void getUser();
}
UserServicelmpl业务实现类
public class UserServiceImpl implements UserService{
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
public void getUser(){
userDao.getUser();
}
}
MyTest
public class MyTest {
public static void main(String[] args) {
//用户实际调用的是业务层
UserService userService = new UserServiceImpl();
((UserServiceImpl)userService).setUserDao(new UserDaoOracleImpl());
userService.getUser();
}
}
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
之前,程序主动创建对象,控制权在程序
使用set注入,程序变成了被动接收对象
控制反转是一种通过描述(XML或注解)及第三方去生产或获取特定对象的方式
可使用XML配置
采用XML方式配置Bean,Bean的定义与实现分离
使用注解配置
采用注解方式将Bean的定义和实现合为一体
Bean的定义信息直接以注解的形式定义在实现类中,从而达到零配置目的
IOC是一种设计思想,DI(依赖注入)是实现IOC的一种方法,在Spring中实现IoC的是IoC容器
控制反转:获得对象的方式反转
依赖注入
Spring通过IoC容器完成对实例的创建,装配,管理
Theorg.springframework.beans
andorg.springframework.context
packages are the basis for Spring Framework’s IoC container.
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>5.2.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.0.RELEASEversion>
dependency>
<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="userServiceImpl" class="com.kuang.service.UserServiceImpl">
<property name="userDao" ref="userDaoMysqlImpl"/>
bean>
beans>
The BeanFactory
interface provides an advanced configuration mechanism capable of managing any type of object. ApplicationContext
is a sub-interface of BeanFactory
.
BeanFactory
定义了能够管理所有类的配置机制,ApplicationContext
是其子接口
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("");
The ApplicationContext
is the interface for an advanced factory capable of maintaining a registry of different beans and their dependencies. By using the method T getBean(String name, Class
, you can retrieve instances of your beans.
ApplicationContext
是维护不同bean及其相关依赖的注册工厂
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//对象由主动创建变为被动接收
UserService userService = (UserServiceImpl) applicationContext.getBean("userServiceImpl");
userService.getUser();
}
<bean id="hello" class="com.kuang.pojo.Hello" name="hello2,u2">
<constructor-arg name="str" value="Spring"/>
bean>
中配置的是交给IoC容器管理的类资源
property name
element refers to the name of the JavaBean propertyref
element refers to the name of another bean definition.The id
attribute is a string that identifies the individual bean definition.
The class
attribute defines the type of the bean and uses the fully qualified classname.
全限定名
:包名.类型
If you want to introduce other aliases
for the bean, you can also specify them in the name
attribute, separated by a comma (,
), semicolon (;
), or white space
<bean id="hello" class="com.kuang.pojo.Hello">
<constructor-arg name="str" value="Spring"/>
bean>
<alias name="hello" alias="h"/>
将多个配置文件导入到一个,便于统一管理
<import resource="beans1.xml">
<import resource="beans2.xml">
<import resource="beans3.xml">
在配置文件加载时,容器中管理的对象就已被初始化
下标赋值-index
<bean id="hello" class="com.kuang.pojo.Hello">
<constructor-arg index="0" value="Spring"/>
bean>
参数类型匹配-type
<bean id="hello" class="com.kuang.pojo.Hello">
<constructor-arg type="java.lang.String" value="Spring"/>
bean>
直接通过参数名设置-name
<bean id="hello" class="com.kuang.pojo.Hello">
<constructor-arg name="str" value="Spring"/>
bean>
public class Student {
private String name;//基本数据类型 DI
private Address address;//引用数据类型 DI
private String[] books;//数组 DI
private List<String> hobbys;//List DI
private Map<String,String> card;// Map DI
private Set<String> games;//Set DI
private String wife;//null DI
private Properties info;//properties DI
}
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="Auspice Tian"/>
bean>
<bean id="beijing" class="com.kuang.pojo.Address">
<property name="address" value="北京"/>
bean>
<bean id="student" class="com.kuang.pojo.Student">
<property name="address" value="beijing"/>
bean>
<property name="books">
<array>
<value>红楼梦value>
<value>西游记value>
<value>水浒传value>
<value>三国演义value>
array>
property>
<property name="hobbys">
<list>
<value>gggvalue>
<value>pppvalue>
<value>zzzvalue>
list>
property>
<property name="card">
<map>
<entry key="身份证" value="123456789111111"/>
<entry key="学生证" value="123456489789789"/>
map>
property>
<property name="games">
<set>
<value>LOLvalue>
<value>COCvalue>
<value>BOBvalue>
set>
property>
<property name="wife">
<null>null>
property>
<property name="info">
<props>
<prop key="driver">driverprop>
<prop key="url">urlprop>
<prop key="username">rootprop>
<prop key="password">2017002231prop>
props>
property>
可直接注入基本数据类型和bean
导入约束:xmlns:p=“http://www.springframework.org/schema/p”
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="john-modern" class="com.example.Person"
p:name="John Doe"
p:spouse-ref="jane"/>
<bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
bean>
beans>
导入约束:xmlns:c=“http://www.springframework.org/schema/c”
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="[email protected]"/>
bean>
<bean id="beanOne" class="x.y.ThingOne"
c:thingTwo-ref="beanTwo"
c:thingThree-ref="beanThree"
c:email="[email protected]"/>
beans>
<bean id="student" class="com.kuang.pojo.Student" scope="singleton | prototype">
Scope | Description |
---|---|
singleton | (Default ) Scopes a single bean definition to a single object instance for each Spring IoC container.全局唯一 |
prototype | Scopes a single bean definition to any number of object instances. |
request | Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext . |
session | Scopes a single bean definition to the lifecycle of an HTTP Session . Only valid in the context of a web-aware Spring ApplicationContext . |
application | Scopes a single bean definition to the lifecycle of a ServletContext . Only valid in the context of a web-aware Spring ApplicationContext . |
websocket | Scopes a single bean definition to the lifecycle of a WebSocket . Only valid in the context of a web-aware Spring ApplicationContext . |
Spring会在上下文中自动寻找,自动装配属性
<bean id="cat" class="com.kuang.pojo.Cat" />
<bean id="dog" class="com.kuang.pojo.Dog" />
<bean id="person" class="com.kuang.pojo.Person">
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
<property name="name" value="Auspice Tian"/>
bean>
setter的形参名与容器中的bean.id相同
bean的id唯一
<bean id="person" class="com.kuang.pojo.Person" autowire="byName" />
属性类型与bean类型相同
与属性类型相同的Bean唯一
<bean id="person" class="com.kuang.pojo.Person" autowire="byType" />
最佳实践:XML用于管理Bean,注解用于管理属性注入
Spring 2.5开始支持注解开发,JDK1.5支持注解
在Spring4之后,若使用注解开发,还必须保证 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/context https://www.springframework.org/schema/context/spring-context.xsd”
配置注解的支持
指定要扫描的包,该包下的注解会生效
<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:component-scan base-package="com.kuang.pojo"/>
<context:annotation-config/>
beans>
@Component
——bean组件,放在类上,说明这个类被Spring管理,就是Bean
/*
* @Component 相当于
* */
@Component
public class User {
private String name = "Auspice Tian";
/* setters and getters */
}
在Web开发中,会按照MVC分层,与@Component
等价
@Repository
@Service
@Controller
@Value("")
——属性通过注解注入,在属性与属性的setters()上注入等价
@Component
public class User {
@Value("Auspice Tian")
private String name;
@Value("Auspice Tian")
public void setName(String name) {
this.name = name;
}
}
@AutoWired
@AutoWired(required=false)
:表示该注解修饰的内容可以为空
@Qualifier(value="cat1111")
@Nullable
:表示这个注解修饰的内容允许为Null
@Resource
@Resource(name="指定bean.id")
@Scope("")
JavaConfig是Spring的子项目,Spring4后,称为核心功能
//com.config.AppConfig.java
@Configuration
//相当于 由IoC容器托管,被@Component注解
@Import(AppConfig2.class)//导入其他配置文件
@ComponentScan("com.kuang")//指定扫描的包,使包下注解生效
public class AppConfig {
@Bean
/* 注册一个Bean 相当于
* 返回值类型相当于 bean.class
* 函数名相当于bean.id
* */
public User user(){
return new User(); //返回要注入到容器中的对象
}
}
对目标类的调用由直接调用变为间接调用
在代理类调用目标类之前和之后做一些预处理和后处理操作,用来扩展一些不属于目标类的功能
比如:可以在方法开始和结束前记录日志;在方法执行前进行额外的参数校验;进行事务管理,权限校验
在程序运行之前,就为给真实角色编写并编译了代理角色的代码,生成代理角色的字节码文件,在程序运行时,直接运行这些字节码文件
如在租房的服务中:
抽象角色
/* 抽象角色 */
public interface Rent {
public void rent();
}
真实角色
/* 真实角色 */
public class Host implements Rent{
public void rent(){
System.out.println("房东出租房子");
}
}
代理角色
/* 代理角色 */
public class Agent implements Rent{
Host host;
public Agent(Host host) {
this.host = host;
}
public void rent(){
visit();
host.rent();
assign();
fare();
}
public void visit(){
System.out.println("预约看房");
}
public void assign(){
System.out.println("签合同");
}
public void fare(){
System.out.println("收中介费");
}
}
客户访问代理角色
/* 客户 */
public class Client {
public static void main(String[] args) {
Host host = new Host();
Agent agent = new Agent(host);
agent.rent();
}
}
在实现日志功能时
抽象角色
/*用户服务:抽象角色*/
public interface UserDao {
public void add();
public void delete();
public void update();
public void query();
}
真实角色
/*实现用户服务功能:真实角色*/
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("实现新增用户");
}
@Override
public void delete() {
System.out.println("实现删除用户");
}
@Override
public void update() {
System.out.println("实现更新用户");
}
@Override
public void query() {
System.out.println("实现查询用户");
}
}
代理角色
public class Proxy implements UserDao{
UserDaoImpl user;
public void setUser(UserDaoImpl user) {
this.user = user;
}
@Override
public void add() {
log("add");
user.add();
}
@Override
public void delete() {
log("delete");
user.delete();
}
@Override
public void update() {
log("update");
user.update();
}
@Override
public void query() {
log("query");
user.query();
}
public void log(String msg){
System.out.println("[DEBUG]实现"+msg+"日志功能!");
}
}
用户
/*使用用户功能:客户*/
public class Client {
public static void main(String[] args) {
UserDaoImpl user = new UserDaoImpl();
Proxy proxy = new Proxy();
proxy.setUser(user);
proxy.add();
proxy.query();
proxy.update();
proxy.delete();
}
}
优点:
缺点:
在运行态,通过反射自动生成代理角色
java.lang.reflect.Proxy
,实现 InvocationHandler
接口,实现它的 invoke()
方法
获取代理类
public static Object newProxyInstance
(ClassLoader loader,
@NotNull Class<?>[] interfaces,
@NotNull reflect.InvocationHandler h)
//params
loader – the class loader to define the proxy class
interfaces – the list of interfaces for the proxy class to implement
h – the invocation handler to dispatch method invocations to
//return
a proxy instance with the specified invocation handler of a proxy class that is defined by the specified class loader and that implements the specified interfaces
Interface InvocationHandler
:When a method(抽象角色–>接口) is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
每个被代理实例都有一个关联的调用处理程序
静态代理对应的动态代理
抽象角色
public interface Rent {
public void rent();
}
真实角色
public class Host implements Rent{
public void rent(){
System.out.println("房东要出租房屋!");
}
}
动态代理角色
调用处理程序动态生成代理角色、绑定真实角色
//代理处理程序:自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//需要被代理的抽象角色-->接口
Rent rent;
//通过DI注入真实角色
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理角色
public Object getProxy(){
return Proxy.newProxyInstance(
//抽象角色的类加载器
rent.getClass().getClassLoader(),
//抽象角色的接口
rent.getClass().getInterfaces(),
//该抽象角色的代理处理程序
this);
}
//处理代理类实例;返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
visit();
Object result = method.invoke(rent,args);
assign();
fare();
return result;
}
/*公共业务*/
public void visit(){
System.out.println("看房");
}
public void assign(){
System.out.println("签合同");
}
public void fare(){
System.out.println("中介费");
}
}
客户
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//通过InvocationHandler处理要被调用的抽象角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//调用处理程序与真实角色的绑定
pih.setRent(host);
//生成代理角色
Rent proxy = (Rent)pih.getProxy();
proxy.rent();
}
}
抽象角色–>接口
public interface UserDao {
public void add();
public void delete();
public void update();
public void query();
}
真实角色–>被代理类
public class UserDaoImpl implements UserDao{
@Override
public void add() {
System.out.println("add");
}
@Override
public void delete() {
System.out.println("delete");
}
@Override
public void update() {
System.out.println("update");
}
@Override
public void query() {
System.out.println("query");
}
}
动态代理角色
调用处理程序–>动态生成代理类的程序
public class ProxyInvocationHandler implements InvocationHandler {
//被调用的接口——>抽象角色
private Object target;
//注入真实角色
public void setTarget(Object target) {
this.target = target;
}
//返回代理类
public Object getProxy(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(target.getClass().getName());
Object result = method.invoke(this.target,args);
return result;
}
/*公共业务*/
public void log(String msg){
System.out.println("[DEBUG]调用了"+msg+"方法");
}
}
客户
public class Client {
public static void main(String[] args) {
//定义调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//调用处理程序与将代理角色与真实角色绑定
pih.setTarget(new UserDaoImpl());
//获取代理角色,,代理的是接口
UserDao proxy = (UserDao) pih.getProxy();
proxy.add();
proxy.query();
proxy.update();
proxy.delete();
}
}
好处
(Aspect Oriented Programming):面向切面编程
通过 预编译方式和动态代理 实现程序功能的统一维护的技术,就是 Spring对动态代理的实现
提供声明式事务;允许用户自定义切面
将Service层抽象为的接口作为 抽象角色 ,Service的实现类作为 真实角色 。Spring为我们完成了动态代理中 代理角色(即 Aspect
可以理解为一个代理)的创建,我们需要做的是
invoke()
方法中公共函数,对应于 通知 Advice
若使用自定义切面,则只需要在切面中实现通知,切入点由注解定义,然后将切面注册到IoC容器中
实现这些切点通知,在配置文件中配置这些切点通知作用在哪些Bean上
通知类型 | 连接点 | 需实现的接口 |
---|---|---|
前置通知 | 方法前 | org.springframework.aop.MethodBeforeAdvice; |
后置通知 | 方法后 | org.springframework.aop.AfterReturningAdvice |
环绕通知 | 方法前后 | org.aopalliance.intercept.MethodInterceptor |
异常抛出通知 | 方法抛出异常时 | org.springframework.aop.ThrowsAdvice |
引介通知 | 类中新增方法或属性 | org.springframework.aop.IntroductionInterceptor |
public interface UserService {
public void add();
public void delete();
public int select();
public void update();
}
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("addService");
}
@Override
public void delete() {
System.out.println("deleteService");
}
@Override
public int select() {
System.out.println("selectService");
return 1;
}
@Override
public void update() {
System.out.println("updateService");
}
}
/*代理要做的公共业务 通知 Log.java
* implements 通过Advice定义切入点pointcut
* */
public class Log implements MethodBeforeAdvice {
/*
* method:要执行的目标对象的方法
* objects:参数
* o:目标对象 target-->接口
* */
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("执行了"+o.getClass().getName()+"的"+method.getName());
}
}
/*代理对象的一个公共业务-->通知 AfterLog.java
* implements 通过Advice定义切入点pointcut
* */
public class AfterLog implements AfterReturningAdvice {
@Override
/*
* o:返回值
* method:要执行的目标对象的方法
* objects:args
* o1:目标对象 target-->接口
* */
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("执行了"+o1.getClass().getName()+"的"+method.getName()+"-返回值为:"+o);
}
}
<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">
<bean id="userServiceImpl" class="com.kuang.service.UserServiceImpl"/>
<bean id="log" class="com.kuang.log.Log"/>
<bean id="afterlog" class="com.kuang.log.AfterLog"/>
<aop:config>
<aop:pointcut id="pc_userService" expression="execution(* com.kuang.service.UserServiceImpl.*(..))" />
<aop:advisor advice-ref="log" pointcut="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="afterlog" pointcut-ref="pc_userService"/>
aop:config>
beans>
格式
execution( modifiers-pattern?
ret-type-pattern declaring-type-pattern?
name-pattern(param-pattern) throws-pattern?)
自定义切面,在配置文件中将切面中的通知与切点表达式绑定
public class DiyAspect {
public void before(){
System.out.println("=========实现前置通知==========");
}
public void after(){
System.out.println("==========实现后置通知==========");
}
}
<bean id="diy" class="com.kuang.advisor.DiyAspect" />
<aop:config>
<aop:pointcut id="pc_userService" expression="execution(* com.kuang.service.UserServiceImpl.*(..))" />
<aop:aspect ref="diy">
<aop:before method="before" pointcut-ref="pc_userService"/>
<aop:after method="after" pointcut-ref="pc_userService"/>
aop:aspect>
aop:config>
利用内置注解,实现切面内的通知
由注解决定通知相对于主逻辑切点的位置
- @Before:前置通知
- @After:后置通知
- @AfterReturn:返回后通知
- @AfterThrowing:出现异常后通知
- @Around:环绕通知
@Aspect
@Component
public class AnnotationAspect {
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("======方法执行前====");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("======方法执行后====");
}
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
//
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
jp.proceed();
System.out.println("环绕后");
}
}
<bean id="diyaspect" class="com.kuang.Aspect.AnnotationAspect" />
<aop:aspectj-autoproxy/>
Spring Bean从创建到被销毁的过程,叫Bean的生命周期
定义Bean,创建BeanDefinition实例,BeanDefinition类中定义了很多属性用于描述Bean,如beanClass(Bean的类型),scope(一个Bean的作用范围),primary,islazy,dependsOn(创建之前所依赖的其他Bean),initMethodName(初始化方法)等
构造方法推断,最终选出一个构造方法
实例化,利用构造方法反射得到一个实例。在Spring中,可以通过 PostProcessor
对Bean的实例化过程进行干预
属性填充,被 @AutoWired
或者 @Resource
注解的属性,需要进行属性填充
初始化前,由 @PostConstruct
注解的方法进行初始化前操作
初始化:Spring提供了初始化机制,可以通过实现 InitializingBean接口中的afterpropertiesSet()方法
或 由@Bean中initMethod属性
指出初始化方法,完成Bean的自定义赋值或校验
初始化后处理
如果当前Bean实现了 ApplicationListener
接口,把它添加到事件监听器列表中
若开启了AOP,则判断当前实例的中的方法是否是某一切面的切点,若是,则生成代理对象作为Bean,注册到Spring容器中
在初始化后,生成真正的Bean,将Bean注册到Spring容器以及缓存中
当Spring上下文销毁时,会将其中所有的Bean一并销毁
其中重要的部分是Bean的创建过程
1)利用Class的构造方法,反射得到对应的对象
//定义一个Bean
@Component
public class Userservice{
public void test(){
}
}
public class Test{
public static void main(String[] args){
//创建一个Spring容器
AnnotationConfigApplication applicationContext = new AnnotationContext(AppConfig.class);
//从容器中获取userService Bean
applicationContext.getBean("userService".Userservice.class);
}
}
2)给Bean中的属性赋值
//新定义一个
@Component
public class OrderService{
}
//定义一个Bean
@Component
public class Userservice{
//自动注入另一个Bean
@Autowired
private OrderService orderService;
public void test(){
}
}
public class Test{
public static void main(String[] args){
//创建一个Spring容器
AnnotationConfigApplication applicationContext = new AnnotationContext(AppConfig.class);
//从容器中获取userService Bean
applicationContext.getBean("userService".Userservice.class);
}
}
3)自定义部分属性的初始化
public class User{}
@Component
public class OrderService{
}
//定义一个Bean
@Component
public class Userservice implement InitializingBean{
//自动注入另一个Bean
@Autowired
private OrderService orderService;
private User defaultuser;
@Override
public void afterPropertiesSet(){
//其他的自定义初始化动作
}
@PostConstruct
public void xxx(){
//其他的自定义初始化动作
}
public void test(){
}
}
public class Test{
public static void main(String[] args){
//创建一个Spring容器
AnnotationConfigApplication applicationContext = new AnnotationContext(AppConfig.class);
//从容器中获取userService Bean
applicationContext.getBean("userService".Userservice.class);
}
}
4)若开启AOP且是切面的一个切点,则生成一个代理对象
@Aspect
@Component
public class MyAspect{
public AspectBefore(){
@Before("execution(public void packageName.service.Uservice.test())")
System.out.println("Before");
}
}
判断是否进行AOP:
在定义一个切面时,会用 @Aspect
,@Component
注解切面,此时将切面的切点与当前实例进行比较。
若切点匹配成功,则进行动态代理,产生代理对象
UserserviceProxy extends Userservice{
private Userservice targer;
@Override
public test(){
//执行切面的代理逻辑
System.out.println("Before");
target.test();
}
}
代理对象不做属性填充
@PostConstruct
注解的方法,则进行相应的初始化前操作InitializingBean
接口的 afterPropertiesSet()
方法 ,再调用 @Bean
中的 initMethod
属性配置的初始化方法ApplicationListener
接口的Bean添加到事件监听器列表中若有被 @Autowired
注解的构造器,则调用该构造器
若有参和无参构造方法同时存在,优先选无参构造器
若只有一个构造器,则使用唯一的构造器
若没有声明构造器,则用无参构造器
若没有无参构造器且有多个有参构造器,则抛出异常
Spring容器中同一个类可以有多个不同名称的Bean
单例模式:一个类只有一个实例
单例Bean:一个Spring容器只有一个同类型的同名Bean
applicationContext.getBean("orderService")
执行多次,得到的是同一个Bean@Component//配置类
public class AppConfig{
@Bean
public OrderService orderservice1(){
return new OrderService();
}
@Bean
public OrderService orderservice1(){
return new OrderService();
}
@Bean
public OrderService orderservice2(){
return new OrderService();
}
}
执行后,
被 @Autowired
注解的属性,从Spring容器中找合适的Bean给属性赋值
@Bean(autowiredCandidate=false)
的Bean@Qualifier("")
注解中指明Bean所在的目标分组,第二轮筛选会剔除不在该分组的Bean@Primary
注解的Bean,则选择主Bean注入@Priority()
设置了Bean的不同优先级,选择优先级最高的Bean注入<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.6version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.16version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.3version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.3version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.16version>
dependency>
dependencies>
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
build>
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name=""/>
typeAliases>
<settings>
<setting name="" value=""/>
settings>
configuration>
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.mapper.UserMapper">
<select id="getUsers" resultType="user">
select *from mybatis.user;
select>
mapper>
<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">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="2017002231"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"/>
bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
beans>
+从properties文件导入
#db.properties
mysql_driver=com.mysql.cj.jdbc.Driver
mysql_url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
root=root
root_pwd=2017002231
<beans xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:db.properties"/>
public class UserMapperImpl implements UserMapper{
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> getUsers() {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
return userMapper.getUsers();
}
}
<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">
<import resource="spring-mybatis.xml"/>
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
bean>
beans>
<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">
<import resource="spring-mapper.xml"/>
beans>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
List<User> users = userMapper.getUsers();
for (User user : users) {
System.out.println(user);
}
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.6version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.16version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.3version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.3version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.16version>
dependency>
dependencies>
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
build>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name=""/>
</typeAliases>
<settings>
<setting name="" value=""/>
</settings>
</configuration>
mysqlDriver=com.mysql.cj.jdbc.Driver
mysqlUrl=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
root=root
rootPassword=2017002231
<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
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="db.properties"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${mysqlDriver}"/>
<property name="url" value="${mysqlUrl}"/>
<property name="username" value="${root}"/>
<property name="password" value="${rootPassword}"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"/>
bean>
beans>
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
<select id="getUsers" resultType="user">
select * from mybatis.user;
select>
mapper>
继承 Spring的SqlSession类
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
@Override
public List<User> getUsers(){
return getSqlSession().getMapper(UserMapper.class).getUsers();
}
}
<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">
<import resource="spring-mybatis.xml" />
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
beans>
<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">
<import resource="spring-mapper.xml"/>
beans>
ACID:
原子性(Atom)
一致性(Consistent)
隔离性(Isolation):多个事务并发执行,防止数据损坏
持久性(durablity):事务一旦提交,无论系统发生什么问题,结果都不会被影响
<mapper namespace="com.kuang.mapper.UserMapper">
<select id="getUsers" resultType="user">
select * from mybatis.user;
select>
<insert id="addUser" parameterType="user">
insert into user (id,user_name,pwd) values (#{id},#{user_name},#{pwd});
insert>
<delete id="deleteUser">
deletes from user where id = #{id};
delete>
mapper>
public void op(){
User user = new User(10,"transaction","123123");
addUser(user);
deleteUser(10);
}
<bean id="transaction" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:advice id="txAdvice" transaction-manager="transaction">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="pc_tx" expression="execution(* com.kuang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc_tx"/>
aop:config>