入门
使用Maven引入Spring6基础依赖环境:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.2</version>
</dependency>
</dependencies>
在Bean.xml
文件完成对象创建,<bean id="user" class="com.atguigu.spring6.User"></bean>
,id是唯一标识,class是对象所在类的全路径。
在项目中调用该对象的步骤:
//加载Spring配置文件,创建对象
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//获取创建的对象
User user = (User) context.getBean("user");
//使用对象调用方法进行测试
user.add();
创建过程中调用了类的无参数构造方法,根据bean.xml
文件的class属性利用反射创建对象,创建好的对象则放在一个Map中。
Log4j2
Apache Logj2是一个开源的日志记录组件,使用非常的广泛。在工程中以易用方便代替了System.out等打印语句,它是JAVA下最流行的日志输入工具。
Log4j2的组成:
- 日志信息的优先级,日志信息的优先级从高到低有TRACE<DEBUG<INFO<WARN<ERROR<FATAL。这些级别分别用来指定这条日志信息的重要程度;级别高的会自动屏蔽级别低的日志。
- 日志信息的输出目的地。
- 日志信息的输出格式。
引入Log4j2依赖:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.19.0</version>
</dependency>
引入依赖文件后,需要在类的根路径(resources文件内)下提供log4j2.xml
文件,文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<loggers>
<!--选择日志的级别-->
<root level="DEBUG">
<appender-ref ref="spring6log"/>
<appender-ref ref="RollingFile"/>
<appender-ref ref="log"/>
</root>
</loggers>
<appenders>
<!--输出日志信息到控制台-->
<console name="spring6log" target="SYSTEM_OUT">
<!--控制日志输出的格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
</console>
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
<File name="log" fileName="D:/java/尚硅谷2023最新版spring6课程/log/test.log" append="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>
<!-- 这个会打印出所有的信息,
每次大小超过size,
则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,
作为存档-->
<RollingFile name="RollingFile" fileName="D:/java/尚硅谷2023最新版spring6课程/log/app.log"
filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
<SizeBasedTriggeringPolicy size="50MB"/>
<!-- DefaultRolloverStrategy属性如不设置,
则默认为最多同一文件夹下7个文件,这里设置了20 -->
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</appenders>
</configuration>
写入日志:
//创建对象,记得导入的是org.slf4j.*
private Logger logger = LoggerFactory.getLogger(TestUser.class);
//写入日志
logger.info("执行调用成功。。");
容器:IoC
loC是Inversion of Control的简写,译为"控制反转",它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序。
Spring通过loc容器来管理所有Java对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由IoC容器管理的Java对象称为Spring Bean,它与使用关键字new创建的Java对象没有任何区别T
Spring提供了IoC容器的两种实现方式:1、BeanFactory这是IoC容器的基本实现,是Spring内部使用的接口。面向Spring本身,不提供给开发人员使用。2、ApplicationContext:BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory。
根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看:对象instanceof指定的类型的返回结果,只要返回的是true就可以认定为和类型匹配,能够获取到。因此当bean唯一时,可以根据接口来获取实现类。
遇到Maven导入包失败的时候可以检查一下仓库的路径设置,因为设置文件是改过的,因此使用原来的设置可能会出现导包不成功的情况。
遇到java: 程序包com.sun.tools.javac不存在
的问题可以到JDK8中导入tools.jar
文件,详细教程。
FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的 bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。将来我们整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。
自动装箱方式有byType
和byName
两种,可以通过Bean标签中的autowire
属性设置。
基于xml方式管理Bean
获取Bean的方式
- 根据ID获取Bean。
User user = (User) context.getBean("user");
。 - 根据类型获取Bean。
User user2 = (User) context.getBean(User.class);
。当根据类型获取Bean时,要求IoC容器内指定的Bean有且只有一个,否则会出现错误。 - 根据ID和类型获取Bean。
User user3 = (User) context.getBean("user",User.class);
。
依赖注入方式
DI(Dependency Injection):依赖注入,依赖注入实现了控制反转的思想。依赖注入:指Springt创建对象的过程中,将对象依赖属性通过配置进行注入。
- 通过setter注入:
<bean id="book" class="com.atguigu.spring6.iocxml.di.Book">
<property name="bname" value="前端开发"></property>
<property name="author" value="尚硅谷"></property>
</bean>
- 通过构造器注入:
<bean id="bookCon" class="com.atguigu.spring6.iocxml.di.Book">
<constructor-arg name="bname" value="java"></constructor-arg>
<constructor-arg name="author" value="尚硅谷"></constructor-arg>
</bean>
- P命名空间注入:
<!--首先声明一个P命名空间-->
xmlns:p="http://www.springframework.org/schema/p"
<!-- P命名空间注入-->
<bean id="studentp" class="com.atguigu.spring6.iocxml.dimap.Student"
p:sid="100" p:sname="mary" p:lessonList-ref="lessonList" p:teacherMap-ref="teacherMap">
特殊值处理
- 空值,加上null标签。
<property name="other"><null/></property>
。 - xml实体,即
<>
符号,需要使用<和>
进行转义。 - CDATA区,需要写特殊字符的时候可以使用。
<property name="other"><value><![CDATA[a<b]]></value></property>
。
特殊类型注入
- 对象类型属性注入
<!--引入外部bean,使用ref指向外部bean的ID值-->
<bean id="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="保安部"></property>
</bean>
<bean id="emp" class="com.atguigu.spring6.iocxml.ditest.Emp">
<property name="dept" ref="dept"></property>
</bean>
<!--内部bean注入,在bean中属性再建一个bean-->
<property name="dept">
<bean id="dept2" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="财务部"></property>
</bean>
</property>
<!--级联注入,通过ref属性获取到bean后修改值-->
<bean id="dept3" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="技术部"></property>
</bean>
<bean id="emp3" class="com.atguigu.spring6.iocxml.ditest.Emp">
<property name="dept" ref="dept3"></property>
<property name="dept.dname" value="测试部"></property>
</bean>
- 数组类型属性注入
<property name="loves">
<array>
<value>吃饭</value>
<value>睡觉</value>
<value>敲代码</value>
</array>
</property>
- 集合类型属性注入
<bean id="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="empList">
<list>
<!--因为数组里面的值是对象,因此不适用value属性,而是使用ref-->
<ref bean="empone"></ref>
<ref bean="emptwo"></ref>
</list>
</property>
</bean>
- Map类型属性注入
<property name="teacherMap">
<map>
<entry>
<key><value>100</value></key>
<ref bean="teacher"></ref>
</entry>
</map>
</property>
- 引用集合类型的bean,需要在上面添加命名空间。
<property name="lessonList" ref="lessonList"></property>
<!--在外边写好,然后使用ref引用-->
<util:list id="lessonList">
<ref bean="lessonone"></ref>
<ref bean="lessontwo"></ref>
</util:list>
- 引用外部属性注入,首先引入数据库相关依赖,然后创建外部属性文件,properties格式,最后创建Spring配置文件,引入context命名空间,引入属性文件,使用表达式完成注入。
<!--添加context命名空间-->
<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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--引用外部属性文件-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClassName" value="${jdbc.driver}"></property>
</bean>
作用域
取值 | 含义 | 创建对象的时机 |
---|---|---|
singleton | 在IoC容器中,这个bean的对象始终为单实例 | IoC容器初始化时 |
prototype | bean在IoC容器中有多个实例 | 获取bean时 |
request | 在一个请求范围内有效 | |
session | 在一个会话范围内有效 |
生命周期
初始化方法和销毁方法都可以在bean标签的属性中设置。
- bean对象创建(调用无参构造器)。
- 给bean对象设置属性
- bean的后置处理器(初始化之前),由一个实现
BeanPostProcessor
接口的类执行,后置处理器对整个IoC容器生效。配置文件:<bean id="myBeanProcessor" class="com.atguigu.spring6.iocxml.life.MyBeanPost"></bean>
。 - bean对象初始化(需在配置bean时指定初始化方法)
- bean的后置处理器(初始化之后)
- bean对象就绪可以使用
- bean对象销毁(需在配置bean时指定销毁方法),当使用close()方法时进行销毁。
- IoC容器关闭
基于注解管理Bean(重点)
从Java5开始,Java增加了对注解(Annotation)的支持,它是代码中的一种特殊标记。可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。Spring从2.5版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化Spring的XML配置。 Spring通过注解实现自动装配的步骤如下:1.引入依赖 2.开启组件扫描 3.使用注解定义Bean 4.依赖注入。
组件扫描:Spring默认不使用注解装配Bean,因此我们需要在Spring的XML配置中,通过context:component--scan元素开启Spring Beans的自动扫描功能。开启此功能后,Spring会自动从扫描指定的包(base-package属性设置)及其子包下的所有类,如果类上使用了@Component注解,就将该类装配到容器中。
注解
注解 | 说明 |
---|---|
@Component | 该注解用于描述Spring中的Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如Service层、Dao层等。使用时只需将该注解标注在相应类上即可。 |
@Repository | 该注解用于将数据访问层(Dao层)的类标识为Spring中的Bean,其功能与@Component相同。 |
@Service | 该注解通常作用在业务层(Service层),用于将业务层的类标识为Spring中的Bean,其功能与@Component相同。 |
@Controller | 该注解通常作用在控制层(如SpringMVC的Controller),用于将控制层的类标识为 Spring中的Bean,其功能与@Component相同。 |
@Autowired注入
- 属性注入,在需要注入的属性上写@Autowired注解。
- set方法注入。
- 构造方法注入。
- 形参上注入,把@Autowired写到方法对应的形参上。
- 只有一个构造方法时,可以不使用注解。
- @Autowired注解和@Qualifier注解联合,因为@Autowired默认是使用byType注解的,加上@Qualifier注解则是byName。
@Resource注入
@Resource注入是JDK扩展包,默认使用byName方式装配,@Autowired是Spring框架定义的且默使用byType方式装配。
@Resource注解用在属性上、setter方法上。
@Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖。如果是JDK8的话不需要额外引入依赖。高于DK11或低于JDK8需要引入以下依赖。(这个Maven导入不成功,暂时没解决这个问题)
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
全注解开发
//创建一个配置类,然后指定扫描的目录
@Configuration //配置类
@ComponentScan("com.atguigu.spring6")
public class SpringConfig {
}
//在程序中选择配置类
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
原理-手写IoC
获取Class对象三种方式:1、类名.class;2、对象.getClass();3、Class.forName("类的全路径")。
获取私有方法时需要使用declare方法,而且获取后需要设置允许访问私有属性。
package com.atguigu.bean;
import com.atguigu.anno.Bean;
import com.atguigu.anno.Di;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanNameAware;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* ClassName: AnnotationApplicationContext
* Package: com.atguigu.bean
* Description:
*
* @Author: xiqin
* @Create: 2023 /4/27 - 15:39
* @Version: v1.0
*/
public class AnnotationApplicationContext implements ApplicationContext{
private Map<Class,Object> beanFactory = new HashMap<>();
private static String rootPath;
@Override
public Object getBean(Class clazz) {
return beanFactory.get(clazz);
}
/**
* 创建有参数构造,传递包路径,设置包扫描规则.
*
* @param basePackage the base package
*/
public AnnotationApplicationContext(String basePackage){
try {
//1.把.替换成\
String packagePath = basePackage.replaceAll("\\.", "\\\\");
//2.获取包绝对路径
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);
while (urls.hasMoreElements()){
URL url = urls.nextElement();
//获取到的路径需要解码
String filePath = URLDecoder.decode(url.getFile(), "utf-8");
//获取包前面的路径部分,截取前面的不变部分作为常量
rootPath = filePath.substring(0, filePath.length() - packagePath.length());
System.out.println(filePath);
//包扫描
loadBean(new File(filePath));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
//属性注入
loadDi();
}
private void loadBean(File file) throws Exception {
//1.判断当前是否是文件夹
if(file.isDirectory()){
//2.获取文件夹里面的所有内容
File[] childrenFiles = file.listFiles();
//3。判断文件夹是否为空,不为空则遍历里面的内容
if(childrenFiles == null || childrenFiles.length == 0){
return;
}
for(File child : childrenFiles){
//如果仍是文件夹则进行递归调用
if(child.isDirectory()){
loadBean(child);
} else {
//得到包路径+类名称部分,把前面常量部分截取出来
String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
//判断当前文件夹是否为.class文件
if(pathWithClass.contains(".class")){
String allName = pathWithClass.replaceAll("\\\\", ".").replace(".class","");
Class<?> clazz = Class.forName(allName);
if(!clazz.isInterface()){
Bean annotation = clazz.getAnnotation(Bean.class);
if(annotation != null){
Object instance = clazz.getConstructor().newInstance();
if(clazz.getInterfaces().length > 0){
beanFactory.put(clazz.getInterfaces()[0],instance);
} else {
beanFactory.put(clazz,instance);
}
}
}
}
}
}
}
}
private void loadDi() {
//实例化对象已经在beanFactory的Map集合中
//1.遍历Map集合
Set<Map.Entry<Class, Object>> entries = beanFactory.entrySet();
for(Map.Entry<Class, Object> entry : entries){
//2.获取Map集合中的每个对象,获取到对象属性
Object obj = entry.getValue();
Class<?> clazz = obj.getClass();
Field[] declaredFields = clazz.getDeclaredFields();
//3.遍历得到每个对象属性数组
for(Field field : declaredFields){
//4.判断属性是否有@Di注解,有则进行注入
Di annotation = field.getAnnotation(Di.class);
if(annotation != null){
field.setAccessible(true);
try {
field.set(obj,beanFactory.get(field.getType()));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
面向切面:AOP
代理模式要解决问题是要抽取的代码在方法内部,靠以前把子类中的重复代码抽取到父类的方式没法解决。将核心代码和附加代码分离,难点在于两类代码相互交错。
AOP(Aspect Oriented Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程的一种补充和完善,它以通过预编译方式和运行期动态代理方式实现,在不修改源代码的情况下,给程序动态统一添加额外功能的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
相同目标方法上同时存在多个切面时,切面的优先级控制切面的内外嵌套顺序。使用@Order()
注解可以控制切面的优先级:@Order(较小的数)
:优先级高;@Order(较大的数)
:优先级低。
代理模式
它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来一一解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。
动态代理
package com.atguigu.spring6.aop.example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* ClassName: ProxyFactory
* Package: com.atguigu.spring6.aop.example
* Description:动态代理实现
*
* @Author: xiqin
* @Create: 2023/4/27 - 19:01
* @Version: v1.0
*/
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
/**
* 返回代理对象
*
* @return the object
*/
public Object getProxy(){
//动态生成代理类的类加载器
ClassLoader classLoader = target.getClass().getClassLoader();
//目标对象实现的所有接口的Class类型数组
Class<?>[] interfaces = target.getClass().getInterfaces();
//设置代理对象实现目标对象方法的过程
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用前输出");
//调用目标方法
Object result = method.invoke(target, args);
System.out.println("方法调用后输出");
return result;
}
};
return Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
}
}
//使用时调用即可
public class TestCal {
public static void main(String[] args) {
//CalculatorImpl()是目标代码,需要传入
ProxyFactory proxyFactory = new ProxyFactory(new CalculatorImpl());
Calculator proxy = (Calculator)proxyFactory.getProxy();
proxy.add(1,2);
}
}
相关术语
-
横切关注点:分散在每个各个模块中解决同样的问题,如用户验证、日志管理、事务处理、数据缓存都属于横切关注点。从每个方法中抽取出来的同一类非核心业务。在同一个项目中,我们可以使用多个横切关注点对相关方法进行多个不同方面的增强。
-
通知(增强):想要增强的功能,比如安全,事务,日志等。每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法。五种通知类型:
前置@Before();返回@AfterReturing();异常@AfterThrowing();后置@After();环绕@Around()
。括号中间填入切入点表达式配置切入点,表达式可以通过@Pointcut()
进行重用。 -
切面:封装通知方法的类。
-
目标:被代理的,目标对象。
-
代理:向目标对象应用通知之后创建的代理对象。
-
连接点:Spring中允许你使用通知的地方。
-
切入点:Spring的AOP技术可以通过切入点定位到特定的连接点。通俗说,要实际去增强的方法。
动态代理分类
- JDK代理:有接口,使用JDK动态代理,生成接口实现类代理对象,代理对象和目标对象实现同样的接口。
- cglib代理:没有接口,使用cglib动态代理,生成子类代理对象,通过继承被代理的目标类。
AspectJ:是AOP思想的一种实现。本质上是静态代理,将代理逻辑“织入”被代理的目标类编译得到的字节码文件,所以最终效果是动态的。weaver就是织入器。Spring只是借用了Aspect中的注解。
package com.atguigu.spring6.aop.annoaop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* ClassName: LogAspect
* Package: com.atguigu.spring6.aop.annoaop
* Description:
*
* @Author: xiqin
* @Create: 2023 /5/5 - 17:04
* @Version: v1.0
*/
@Aspect
@Component
public class LogAspect {
//设置切入点和通知类型
//前置方法
@Before(value = "execution(public int com.atguigu.spring6.aop.annoaop.CalculatorImpl.*(..))")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("logger-->前置通知,方法名称"+methodName+"参数:"+ Arrays.toString(args));
}
@After(value = "pointCut()")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("logger-->后置通知,方法名称"+methodName+"参数:"+ Arrays.toString(args));
}
@AfterReturning(value = "execution(* com.atguigu.spring6.aop.annoaop.CalculatorImpl.*(..))",returning = "result")
public void afterReturningMethod(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("logger-->返回通知,方法名称"+methodName+"目标方法返回值:"+ result);
}
@AfterThrowing(value = "execution(* com.atguigu.spring6.aop.annoaop.CalculatorImpl.*(..))",throwing = "ex")
public void afterThrowingMethod(JoinPoint joinPoint,Throwable ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("logger-->异常通知,方法名称"+methodName+"异常信息"+ex);
}
@Around(value = "execution(* com.atguigu.spring6.aop.annoaop.CalculatorImpl.*(..))")
public Object aroundMethod(ProceedingJoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
String argString = Arrays.toString(args);
Object result = null;
try{
System.out.println("环绕通知==目标方法之前执行");
//调用目标方法
result = joinPoint.proceed();
System.out.println("环绕通知==目标方法返回值之后");
}catch (Throwable throwable){
throwable.printStackTrace();
System.out.println("环绕通知==目标方法出现异常执行");
} finally {
System.out.println("环绕通知==目标方法执行完毕");
}
return result;
}
//重用切入点表达式
@Pointcut(value = "execution(* com.atguigu.spring6.aop.annoaop.CalculatorImpl.*(..))")
public void pointCut(){}
}
xml配置
注解方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.atguigu.spring6.aop.annoaop"></context:component-scan>
<!--开启aspectj自动代理,为目标对象生成代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
xml配置方法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.atguigu.spring6.aop.xmlaop"></context:component-scan>
<!-- 配置aop五种通知类型-->
<aop:config>
<!-- 配置切面类-->
<aop:aspect ref="logAspect">
<!-- 配置切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.atguigu.spring6.aop.xmlaop.CalculatorImpl.*(..))"/>
<!-- 配置具体方法-->
<aop:before method="afterMethod" pointcut-ref="pointcut"></aop:before>
<aop:after method="afterMethod" pointcut-ref="pointcut"></aop:after>
<aop:after-returning method="afterReturningMethod" returning="result" pointcut-ref="pointcut"></aop:after-returning>
<aop:after-throwing method="afterThrowingMethod" throwing="ex" pointcut-ref="pointcut"></aop:after-throwing>
<aop:around method="aroundMethod" pointcut-ref="pointcut"></aop:around>
</aop:aspect>
</aop:config>
</beans>
单元测试:JUint
@SpringJUnitConfig(locations = "classpath:bean.xml")
public class SpringTestJunit5{
//注入
@Autowired
private User user;
//测试方法
@Test
public void testUser(){
System.out.println(user);
user.run();
}
}
//Junit4的注解修改为下面两个即可,另外引入的Test类路径中没有api
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:bean.xml")
事务
查询语句:Emp empResult = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<>(Emp.class),1);
。
<!--事务注解开启-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
@Transactional()
注解可以设置事务,可以设置回滚策略,隔离级别,传播行为。
事务的传播行为:在service类中有a方法和b方法,a方法上有事务,b方法上也有事务,当a方法执行过程中调用了b方法,事务是如何传递的?合并到一个事务里?还是开启一个新的事务?这就是事务传播行为。
配置类的编写
@Configuration //配置类
@ComponentScan("com.atguigu.spring6.tx")
@EnableTransactionManagement //开启事务管理
public class SpringConfig {
@Bean
public DataSource getDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("159123zxc");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring?characterEncoding=utf8&useSSL=false");
return dataSource;
}
@Bean(name="jdbcTemplate")
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
Spring Resourcers
Spring的Resource声明了访问low-level资源的能力。
ClassPathResource用来访问类加载路径下的资源,相对于其他的Resource实现类,其主要优势是方便访问类加载路径里的资源,尤其对于Web应用,ClassPathResource可自动搜索位于classes下的资源文件,无须使用绝对路径访问。
Spring提供如下两个标志性接口:1.ResourceLoader:该接口实现类的实例可以获得一个Resource实例。2.ResourceLoaderAware:该接口实现类的实例将获得一个ResourceLoader的引用,这样就可以使用依赖注入。
标签:教程,Spring,Bean,class,bean,注解,Spring6,public From: https://www.cnblogs.com/xiqin-huang/p/17898637.html