| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> SSM【定制化】~ Spring -> 正文阅读 |
|
[Java知识库]SSM【定制化】~ Spring |
一、概述1.1、Spring是什么?
1.2、Spring 的优良特性
1.3、使用 Spring 框架的好处Spring 框架主要的好处:
1.4、依赖注入DI(重点)
1.5、面向切面的程序设计AOP(重点)
二、Spring IOC(重点)2.1、Spring ApplicationContext 容器
2、引入Spring依赖
3、创建测试对象类
4、创建beans.xml配置文件(Spring核心配置文件)
5、创建测试类
测试结果: 总结:从该案例可以发现,我们不需要自己创建对象,而Spring已经帮我们完成了,这就是依赖注入(DI)。 2.2、Spring bean 定义(常用几种)注意: 2.2.1、无参构造
2.2.2、有参构造
2.2.3、SET方法
2.2.4、测试
测试结果: 2.3、Spring 标签(配置文件常用标签)2.3.1、
|
作用域 | 描述 |
---|---|
singleton | 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值(重点) |
prototype | 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()(重点) |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境 |
global-session | 一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext环境 |
作用:singleton 作用域每次返回都是同一个bean对象。
1、创建一个bean
<bean id="person07" class="com.ruanjia.entity.Person" scope="singleton">
<constructor-arg name="id" value="10001" />
<constructor-arg name="name" value="ruanjia01" />
<constructor-arg name="sex" value="0" />
<constructor-arg name="age" value="23" />
</bean>
2、测试
public class BeanMain05
{
public static void main(String[] args)
{
//获取Spring上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person1 = (Person) context.getBean("person07");
Person person2 = (Person) context.getBean("person07");
System.out.println(person1 == person2);
}
}
测试结果:
作用:每次从容中取出的Bean都是一个新的Bean实例。
1、创建一个bean
<bean id="person08" class="com.ruanjia.entity.Person" scope="prototype">
<constructor-arg name="id" value="10001" />
<constructor-arg name="name" value="ruanjia01" />
<constructor-arg name="sex" value="0" />
<constructor-arg name="age" value="23" />
</bean>
2、测试
public class BeanMain06
{
public static void main(String[] args)
{
//获取Spring上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person1 = (Person) context.getBean("person08");
Person person2 = (Person) context.getBean("person08");
System.out.println(person1 == person2);
}
}
测试结果:
自动装配就是指 Spring 容器在不使用 <constructor-arg> 和<property> 标签的情况下,可以自动装配(autowire)相互协作的 Bean 之间的关联关系,将一个 Bean 注入其他 Bean 的 Property 中。
<bean>
元素的 autowire
属性。autowire
属性有五个值,具体说明如下所示:名称 | 说明 |
---|---|
no(默认值) | 默认值 ,表示不使用自动装配,Bean 依赖必须通过 ref 元素定义。 |
byName | 根据 Property 的 name 自动装配,如果一个 Bean 的 name 和另一个 Bean 中的 Property 的 name 相同,则自动装配这个 Bean 到 Property 中。(表示按属性名称自动装配,XML 文件中 Bean 的 id 必须与类中的属性名称相同) |
byType | 根据 Property 的数据类型(Type)自动装配,如果一个 Bean 的数据类型兼容另一个 Bean 中 Property 的数据类型,则自动装配。(XML 文件中 Bean 的 id 与类中的属性名称可以不同,但必须只有一个类型的 Bean,否则出现异常。) |
constructor | 类似于 byType,根据构造方法参数的数据类型,进行 byType 模式的自动装配。(类中构造函数的参数必须在配置文件中有相同的类型) |
autodetect(3.0版本不支持) | 如果 Bean 中有默认的构造方法,则用 constructor 模式,否则用 byType 模式。 |
byName
:按照容器中的 bean 实例 id/name 自动装配bean,通过 setter() 方法自动装配,如果Spring容器中没有找到对应的bean会装配失败。
通过setter方法自动装配(例如:Dog 小写 dog 为 beanName)。
测试案例
步骤一:创建Dog.class
public class Dog
{
static
{
System.out.println("小狗.");
}
}
步骤二:创建Cat.class
public class Cat
{
static
{
System.out.println("小猫.");
}
}
步骤三:创建Persion.class
public class Person
{
private String name;
private Dog test;
private Cat cat;
public void setName(String name) {
this.name = name;
}
//byName模式:通过set方法自动装配bean(Dog小写形式dog为beanName,然后根据这个benaName(dog)去Spring容器中找对应的bean完成自动装配)
public void setDog(Dog test) {
this.test = test;
}
//byName模式:通过set方法自动装配bean
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", dog=" + test +
", cat=" + cat +
'}';
}
}
步骤四:beans.xml注册这三个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
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 定义两个bean -->
<bean id="dog" class="com.ruanjia.Dog" />
<bean id="cat" class="com.ruanjia.Cat" />
<!-- autowire="byName":通过setter方法自动装配bean -->
<bean class="com.ruanjia.Person" autowire="byName">
<property name="name" value="my_test." />
</bean>
</beans>
步骤五:BeanMain01.class
public class BeanMain01
{
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = context.getBean(Person.class);
System.out.println(person);
}
}
运行结果:
byName
:按属性类型装配,按类型自动装配bean,如果Spring容器中存在多个中类型的bean就会出现异常。
通过setter方法自动装配(例如:Dog 小写 dog 为 beanName)。
测试案例
步骤一:创建Dog.class
public class Dog
{
static
{
System.out.println("小狗.");
}
}
步骤二:创建Cat.class
public class Cat
{
static
{
System.out.println("小猫.");
}
}
步骤三:创建Persion.class
public class Person
{
private String name;
private Dog dog;
private Cat cat;
public void setName(String name) {
this.name = name;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", dog=" + dog +
", cat=" + cat +
'}';
}
}
步骤四:beans.xml注册这三个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
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean class="com.ruanjia.Dog" />
<bean class="com.ruanjia.Cat" />
<!-- autowire="byType":通过setter方法的属性类型自动装配 -->
<bean class="com.ruanjia.Person" autowire="byType">
<property name="name" value="my_test." />
</bean>
</beans>
步骤五:BeanMain01.class
public class BeanMain01
{
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = context.getBean(Person.class);
System.out.println(person);
}
}
测试结果:
1、添加context约束支持,在头部beans标签内添加以下约束
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd"
2、开启Spring注解支持
<!-- 开启bean注解支持 -->
<context:annotation-config/>
3、范例
<?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-3.0.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启bean注解支持 -->
<context:annotation-config/>
</beans>
作用:按byType
自动装配,如果找不到对应类型的bean或者找到多同类型bean
会出现异常。
注意:@Autowired可以标注在属性上、方法上和构造器上,来完成自动装配(默认根据类型自动装配)。
public class Person
{
private String name;
private Dog dog;
private Cat cat;
public void setName(String name) {
this.name = name;
}
@Autowired
public void setDog(Dog dog) {
this.dog = dog;
}
@Autowired
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", dog=" + dog +
", cat=" + cat +
'}';
}
}
原理:@Resource默认按byName自动装配,例如,Spring容器中存在多个同类型的bean时,我们使用@resource时没有指定name这时就会根据属性名或者方法属性名设为bean的名称,如果找不到这个名称的bean就会根据byType自动装配,但是Spring容器中存在多个同样类型的bean时就会出现异常。
注意:@Resource可以标注在属性上、方法上和构造器上,来完成自动装配(默认根据类型自动装配)。
public class Person
{
private String name;
private Dog dog;
private Cat cat;
public void setName(String name) {
this.name = name;
}
//按类型自动装配(该类型在Spring中是唯一的,否则会出现异常)
@Resource
public void setDog(Dog dog) {
this.dog = dog;
}
//根据名称自动装配(Spring容器中存在多个同类型的bean时,可以通过name属性来完成bean自动装配)
@Resource(name = "cat")
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", dog=" + dog +
", cat=" + cat +
'}';
}
}
作用:类似@resource(name =“”)通过byName自动装配。
public class Person
{
private String name;
private Dog dog;
private Cat cat;
public void setName(String name) {
this.name = name;
}
@Autowired
@Qualifier("dog")
public void setDog(Dog dog) {
this.dog = dog;
}
@Autowired
@Qualifier("cat")
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", dog=" + dog +
", cat=" + cat +
'}';
}
}
实例化 -> 属性注入值 -> 初始化 -> 使用 -> 销毁。
Bean 就是 BeanDefinition
Spring 容器启动过程中会把 Bean 解析成 BeanDefinition。
最终 Bean 工厂会这个 BeanDefinition 生产一个 Bean 实例。
BeanDefinition 里面里面包含了 bean 定义的各种信息。
实例化、属性赋值、初始化、销毁。
bean就是人的一生。
文章地址:
https://blog.csdn.net/sinat_40770656/article/details/123498761?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165787691216781647529427%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165787691216781647529427&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-11-123498761-null-null.142^v32^control,185^v2^control&utm_term=spring%20bean%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F&spm=1018.2226.3001.4187
添加“init-method”属性,Spring则会在创建对象之后,调用此方法。
添加“destroy-method”属性,Spring则会在销毁对象之前,调用此方法。
工厂的close()方法被调用之后,Spring会毁掉所有已创建的单例对象。
Singleton对象由Spring容器销毁、Prototype对象由JVM销毁。
public class MyBeanService
{
//bean 生命周期初始化方法(初始化执行)
public void init()
{
System.out.println("Bean 初始化.");
}
//bean 生命周期销毁方法(销毁前执行)
public void destroy()
{
System.out.println("Bean 销毁.");
}
}
使用生命周期方法:
<bean id="myBeanService" class="com.ruanjia.service.MyBeanService" init-method="init" destroy-method="destroy" />
@Configuration
public class SpringConfig
{
//在此定义bean的初始化及销毁方法
@Bean(initMethod = "init", destroyMethod = "destroy")
public MyBeanService myBeanService() {
return new MyBeanService();
}
}
public class MyBeanService
{
public MyBeanService()
{
System.out.println("MyBeanService 构造器.");
}
//bean 生命周期初始化方法(初始化执行)
@PostConstruct
public void init()
{
System.out.println("Bean 初始化.");
}
//bean 生命周期销毁方法(销毁前执行)
@PreDestroy
public void destroy()
{
System.out.println("Bean 销毁.");
}
}
AOP的实现有AspectJ、JDK动态代理、CGLIB动态代理。
AOP底层是采用 JDK/CGLIB动态代理实现的。
Aspect Oriented Programming(面向切面编程)。
AOP是OOP的延续,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
静态代理:静态代理说白了就是在程序运行前就已经确定好了的代理对象,代理类和原始类的关系在运行前就已经确定。
静态代理实现条件:
缺点:
代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,【静态代理】在程序规模稍大时就会难以维护。
静态代理类只能为特定的接口(Service)服务。如想要为多个接口服务则需要建立很多个代理类。
优点:
静态代理对客户(测试类)隐藏了被代理类接口(目标类接口)的具体实现类,在一定程度上实现了解耦合,同时提高了安全性!
案例讲解:
1、创建
UserService接口(委托类和代理类统一实现该接口)
//委托类和代理类统一实现该接口
public interface UserService
{
void addUser();
void updateUser();
void deleteUser();
void queryUser();
}
2、创建委托类 UserServiceImpl 实现 UserService 接口(被代理的类)
public class UserServiceImpl implements UserService
{
@Override
public void addUser() {
System.out.println("添加用户.");
}
@Override
public void updateUser() {
System.out.println("更新用户.");
}
@Override
public void deleteUser() {
System.out.println("删除用户.");
}
@Override
public void queryUser() {
System.out.println("查询用户.");
}
}
3、创建代理类(帮别人做某些事情)
public class UserServiceImplProxy implements UserService
{
//注入UserService
private UserService userService;
/**
* 通过setter方法注入委托对象
* @param userService
*/
public void setUserService(UserService userService)
{
this.userService = userService;
}
/**
* 通过构造方法注入委托对象
*/
public UserServiceImplProxy(UserService userService)
{
this.userService = userService;
}
public UserServiceImplProxy()
{
}
//重写下面4个方法:这里就是通过代理的方式为这4个方法做一些处理,例如记录方法执行日志信息等...
@Override
public void addUser() {
log("addUser执行了.");
userService.addUser();
}
@Override
public void updateUser() {
log("updateUser方法执行了.");
userService.updateUser();
}
@Override
public void deleteUser() {
log("deleteUser方法执行了.");
userService.deleteUser();
}
@Override
public void queryUser() {
log("queryUser方法执行了.");
userService.queryUser();
}
private void log(String logName)
{
System.out.println(logName);
}
}
4、测试类
public class MainProxy
{
public static void main(String[] args)
{
//1、由代理对象帮我们操作委托对象。
UserService proxy = new UserServiceImplProxy(new UserServiceImpl());
//2、通过代理调用委托对象方法
proxy.queryUser();
System.out.println("-------------------");
proxy.addUser();
System.out.println("-------------------");
proxy.updateUser();
System.out.println("-------------------");
proxy.deleteUser();
}
}
运行结果:
总结:想要做的事情交给代理对象帮助我们完成即可.
动态代理类的源码是在程序运行期间通过JVM反射等机制动态生成,代理类和委托类的关系是运行时才确定的。
AOP底层就是采用动态代理实现。
动态代理类必须实现Invocation接口,并且实现invoke() 方法,在invoke()方法中需要完成两件事情:一添加服务,二调用业务逻辑方法
**。代理服务就是在代理类中的invoke中执行的。
反射机制
获取目标对象的加载类、接口,还有实现了Invocation接口的代理类传到Proxy.newProxyInstance(被代理类,被代理类接口,代理类)方法
**中获取到代理类的对象实例。2.1、创建委托类接口 UserService
public interface UserService
{
void addUser();
void updateUser();
void deleteUser();
void queryUser();
}
2.2、创建委托类 UserServiceImpl 实现 UserService接口
public class UserServiceImpl implements UserService
{
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void updateUser() {
System.out.println("更新用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
@Override
public void queryUser() {
System.out.println("查询用户");
}
}
3、创建动态代理类(重点)
public class DynamicProxyHandler implements InvocationHandler
{
/* 目标对象(委托类)*/
private Object target;
/**
* 我们可以通过DynamicProxyHandler代理不同类型的对象,如果我们把对外的接口都通过动态代理来实现,
* 那么所有的函数调用最终都会经过 invoke 函数的转发,因此我们就可以在这里做一些自己想做的操作,
* 比如日志系统、事务、拦截器、权限控制等。这也就是AOP(面向切面编程)的基本原理。
*
* @param proxy 目标对象
* @param method 调用方法
* @param args 参数列表
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Object result=null; //返回结果
try{
//原对象方法调用前处理日志信息
System.out.println("---调用目标方法前记录日志---");
//target(委托代理对象),args(目标方法的参数)
result=method.invoke(target, args); //调用目标方法
//原对象方法调用后处理日志信息
System.out.println("---调用目标方法后记录日志---");
}catch(Exception e){
e.printStackTrace();
/* 异常日志打印*/
System.out.println("---error---");
throw e;
}
return result;
}
/**
* 动态生成的代理实例
* @param targetObject 委托代理对象(UserServiceImpl)
* @return
*/
public Object newProxyInstance(Object targetObject)
{
this.target = targetObject;
/**
* 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
* 第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
* 第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
* 第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
* 根据传入的目标返回一个代理对象
*/
return Proxy.newProxyInstance(
targetObject.getClass().getClassLoader(), //获取委托代理对象的类加载器
targetObject.getClass().getInterfaces(), //获取委托对象的实现接口
this //得到InvocationHandler接口的子类实现(DynamicProxyHandler)
);
}
}
4、测试
public class MainProxy02
{
public static void main(String[] args)
{
DynamicProxyHandler handler = new DynamicProxyHandler();
UserService userService = (UserService) handler.newProxyInstance(new UserServiceImpl());
userService.addUser();
userService.updateUser();
}
}
测试结果:
优点:
动态代理实现了只需要将被代理对象作为参数传入代理类就可以获取代理类对象,从而实现类代理,具有较强的灵活性。
动态代理的服务内容不需要像静态代理一样写在每个代码块中,只需要写在invoke()方法中即可,降低了代码的冗余度。
缺点:
根据静态代理的使用,你会发现每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类,所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理。
在静态代理中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象。
在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持。
java.lang.reflect.InvocationHandler接口中的 invoke 定义:
Object proxy:被代理的对象.
Method method:要调用的目标方法.
Object[] args:方法调用时所需要参数.
java.lang.reflect.Proxy类的 newProxyInstance 方法:
包含了jdk代理和cglib代理两种动态代理生成机制.
目标业务类如果有接口则用JDK代理,没有接口则用CGLib代理.
基于接口进行代理。
//目标
final OrderService os = new OrderServiceImpl();
//额外功能
InvocationHandler handler = new InvocationHandler(){//1.设置回调函数(额外功能代码)
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("start...");
method.invoke(os, args);
System.out.println("end...");
return null;
}
};
//2.创建动态代理类
Object proxyObj = Proxy.newProxyInstance(ClassLoader , Interfaces , InvocationHandler);
基于继承代理。
final OrderService os = new OrderServiceImpl();
Enhancer cnh = new Enhancer();//1.创建字节码曾强对象
enh.setSuperclass(os.getClass());//2.设置父类(等价于实现原始类接口)
enh.setCallback(new InvocationHandler(){//3.设置回调函数(额外功能代码)
@Override
public Object invoke(Object proxy , Method method, Object[] args) throws Throwable{
System.out.println("start...");
Object ret = method.invoke(os,args);
System.out.println("end...");
return ret;
}
});
OrderService proxy = (OrderService)enh.create();//4.创建动态代理类
proxy.createOrder();
<!-- Spring 依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- AOP 依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
public interface UserService
{
void addUser();
void deleteUser();
void updateUser();
void queryUser();
}
public class UserServiceImpl implements UserService
{
@Override
public void addUser() {
System.out.println("add User...");
}
@Override
public void deleteUser() {
System.out.println("delete User...");
}
@Override
public void updateUser() {
System.out.println("update User...");
}
@Override
public void queryUser() {
System.out.println("query User...");
}
}
public class LogInfo
{
/* 切入点:execution(* com.ruanjia.service.impl.UserServiceImpl.*(..)) 表示UserServiceImpl下所有方法*/
@Pointcut("execution(* com.ruanjia.service.impl.UserServiceImpl.*(..))")
public void result() {}
/* 前置处理*/
public void before()
{
System.out.println("--------前置处理 记录日志-------");
}
/* 后置处理*/
public void after()
{
System.out.println("--------后置处理 记录日志-------");
}
/* 后置处理*/
public void afterReturning()
{
System.out.println("--------后置处理返回-------");
}
/*
* 环绕通知(增强通知,将目标方法封装起来),可以返回目标方法结果
* ProceedingJoinPoint:程切入点,增强方法在此实现对被增强方法的功能增强。通过切入点我们可以得到很多东西
* */
public void around(ProceedingJoinPoint point)
{
try {
System.out.println("--------环绕通知 前置处理 记录日志-------");
//获取执行的方法名
System.out.println(point.getSignature().getName());
//执行目标方法
point.proceed();
System.out.println("--------环绕通知 后置处理 记录日志-------");
} catch (Throwable throwable)
{
throwable.printStackTrace();
System.out.println("--------环绕通知 异常处理 记录日志-------");
}
}
}
4.1、引入AOP头文件约束
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd"
4.2、本次案例完整Spring-config.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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 定义两个bean -->
<bean id="userService" class="com.ruanjia.service.impl.UserServiceImpl"/>
<bean id="logInfo" class="com.ruanjia.aop.LogInfo"/>
<!-- Aop配置:设置expose-proxy属性为true暴露代理(作用:例如有两个目标方法)。-->
<aop:config>
<!-- 切入点 -->
<aop:pointcut id="qud" expression="execution(* com.ruanjia.service.impl.UserServiceImpl.*(..))"/>
<!-- ref:指定切面类 -->
<aop:aspect ref="logInfo">
<!--
aop:before:前置通知(切入方法执行前执行)
aop:after:前置通知(切入方法执行后执行)
aop:around:环绕通知(围绕着方法执行)
-->
<aop:before method="before" pointcut-ref="qud"/>
<aop:after method="before" pointcut-ref="qud"/>
<aop:around method="around" pointcut-ref="qud"/>
<aop:after-returning method="afterReturning" pointcut-ref="qud"/>
</aop:aspect>
</aop:config>
</beans>
public class AopMain
{
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
//注意:动态代理是代理接口实现,所以必须返回被代理对象实现的接口。
UserService service = context.getBean(UserService.class);
service.addUser();
}
}
<!-- Spring 依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- AOP 依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
//Configuration注解表示这是一个配置类:相当于 ApplicationContext.xml配置文件
@Configuration
//扫描指定包下的所有Spring 容器中的 bean
@ComponentScan("com.ruanjia")
/**
* exposeProxy = true:设置expose-proxy属性为true暴露代理。
* proxyTargetClass = true:设置为true表示使用静态代理(默认 false)
*/
@EnableAspectJAutoProxy //开启AOP代理模式
public class SpringConfig
{
}
public interface UserService
{
void addUser();
void deleteUser();
void updateUser();
void queryUser();
}
//把该类交给Spring容器管理
@Service
public class UserServiceImpl implements UserService
{
@Override
public void addUser() {
System.out.println("add User...");
}
@Override
public void deleteUser() {
System.out.println("delete User...");
}
@Override
public void updateUser() {
System.out.println("update User...");
}
@Override
public void queryUser() {
System.out.println("query User...");
}
}
@Component //由Spring容器管理该对象
@Aspect //表示这是一个切面
public class LogInfo
{
/* 切入点*/
@Pointcut("execution(* com.ruanjia.service.impl.UserServiceImpl.*(..))")
public void result() {}
/* 前置处理*/
@Before("result()")
public void before()
{
System.out.println("--------前置处理 记录日志-------");
}
/* 后置处理*/
@After("result()")
public void after()
{
System.out.println("--------后置处理 记录日志-------");
}
/* 返回结果处理*/
@AfterReturning("result()")
public void afterReturning()
{
System.out.println("--------目标方法返回结果执行-------");
}
/* 环绕通知(增强通知,将目标方法封装起来)*/
//@Around("result()")
public void around(ProceedingJoinPoint point)
{
try {
System.out.println("--------环绕通知 前置处理 记录日志-------");
point.proceed(); //真实执行方法
System.out.println("--------环绕通知 后置处理 记录日志-------");
} catch (Throwable throwable)
{
throwable.printStackTrace();
System.out.println("--------环绕通知 异常处理 记录日志-------");
}
}
}
public class MainAop
{
public static void main(String[] args)
{
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService service = context.getBean(UserService.class);
service.addUser();
}
}
测试结果:
Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理。
每个bean在创建完成之前 ,都会有一个后处理过程,即再加工,对bean做出相关改变和调整.
BeanPostProcessor 接口定义回调方法,你可以实现该方法来提供自己的实例化逻辑,依赖解析逻辑等.
你也可以在
Spring 容器通过插入一个或多个 BeanPostProcessor 的实现来完成实例化,配置和初始化一个bean之后实现一些自定义逻辑回调方法。
注意:ApplicationContext 会自动检测由 BeanPostProcessor 接口的实现定义的 bean,注册这些 bean 为后置处理器,然后通过在容器中创建 bean,在适当的时候调用它。
BeanPostProcessor
,所以它是一个Spring Bean的后置处理器。ApplicationContext
会自动识别,然后通过在容器中创建 bean 时,在适当的时候调用它。public class MyBeanPostProcessor implements BeanPostProcessor
{
//bean 初始化前的后处理
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
{
System.out.println("postProcessBeforeInitialization : " + beanName);
return bean;
}
//bean 初始化后的后处理
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
System.out.println("postProcessAfterInitialization : " + beanName);
return bean;
}
}
public class MyBeanService
{
private String message;
public void setMessage(String message)
{
this.message = message;
}
public void getMessage()
{
System.out.println("Your Message : " + message);
}
//bean 生命周期初始化方法(初始化执行)
public void init(){
System.out.println("Bean init.");
}
//bean 生命周期销毁方法(销毁前执行)
public void destroy()
{
System.out.println("Bean now.");
}
}
<?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-3.0.xsd">
<bean id="myBeanService" class="com.ruanjia.service.MyBeanService" init-method="init" destroy-method="destroy">
<property name="message" value="hello r"/>
</bean>
<!-- 所有bean的后置处理器(只需要放到Spring容器中,容器会自动识别) -->
<bean class="com.ruanjia.postproce.MyBeanPostProcessor"/>
</beans>
public class MyMain
{
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
MyBeanService bean = context.getBean(MyBeanService.class);
bean.getMessage();
}
}
运行结果:
事务是逻辑上的一组操作,要么都执行,要么都不执行。
要么成功(提交事务),要么失败(事务回滚)。
一个业务方法中包含了多个原子性的操作(数据库操作增删改操作)时,要么成功,要么失败(这就是事务)。
事务能否生效数据库引擎是否支持事务是关键。比如常用的 MySQL 数据库默认使用支持事务的
innodb引擎。但是,如果把数据库引擎变为
myisam,那么程序也就不再支持事务了!
//下面方法业务,包含了两个原子性操作。所以要么都执行成功,要么都执行失败。
public void saveUser()
{
userMapper.saveUser(user);
userRoleMapper.saveUserRoles(user, role);
}
回滚
**,在 MySQL 中,恢复机制是通过 回滚日志(undo log)
实现的,所有事务进行的修改都会先记录到这个回滚日志中,然后再执行相关的操作。回滚日志
中的信息将数据回滚到修改之前的样子即可!并且,回滚日志会先于数据持久化到磁盘上
。这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志来回滚将之前未完成的事务。TransactionTemplate
或者TransactionManager
手动管理事务,实际应用中很少使。推荐使用(代码侵入性最小),实际是通过 AOP 实现(基于
@Transactional 的全注解方式使用最多)。
结束语:事务后面在Spring 整合 SpringMVC讲解!!!Spring就讲到这够用了!!!想深入了解Spring自行摸索!!!
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 15:27:33- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |