Spring Aop,Spring Bean,Spring XML
作者:互联网
Spring AOP
前置知识
AOP(Aspect Oriented Programming):面向切面编程,是Spring 早期版本的核心功能,负责管理对象生命周期与对象装配。为了实现对象的管理和装配,一个自然而然的想法就是,加一个中间层代理(字节码增强)来实现所有对象的托管。
IoC(Inversion of Control):控制反转。也称为DI(Dependency Injection) 依赖注入。
对象装配思路的改进:
从对象A 直接引用和操作对象B,变成对象A 里指需要依赖一个接口IB,系统启动和装配阶段,把IB 接口的实例对象注入到对象A,这样A 就不需要依赖一个IB 接口的具体实现,也就是类B。从而可以实现在不修改代码的情况,修改配置文件,即可以运行时替换成注入IB 接口另一实现类C的一个对象实例。
依赖问题:
属性依赖可以解决。A属性里面用到了B,B的属性里面用到了A。创建A对象的时候发现A的属性里需要一个B对象,那么就会创建一个B对象将其塞到A对象中去。创建B对象的时候发现B的属性里需要A,就把A塞到B对象里。
构造器依赖不可以解决。A的构造器里面用到了B,B的构造器里面用到了A不能解决。创建A的时候,发现A对象需要用到B对象;创建B对象的时候,发现B对象需要A对象。
@Autowired和@Resource
//@Autowired按bean的类型注入
//@Autowired(required = false);懒加载,等到Class被使用的时候才开始进行注入
//所以不会在程序启动时就开始检查
@Autowired(required = true)
//@Resource按bean的Id进行注入
@Resource(name = "student100")
使用AOP
xml配置AOP
被代理的接口InterfaceSchool
package io.simon.aop;
/**
* 被代理的接口
*/
public interface InterfaceSchool {
/**
* 铃声ding
*/
void ding();
}
该接口有一个实现类School
package io.simon.aop;
public class School implements InterfaceSchool {
@Override
public void ding() {
System.out.println("ding ....... 上课了");
}
}
假设需要在ding方法上做增强,定义一个AOP
package io.simon.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class Aop1 {
//前置通知
public void start() {
System.out.println("====>begin ding... ");
}
//后置通知
public void end() {
System.out.println("====>finish ding... ");
}
//环绕通知
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("====>around begin ding");
//调用process()方法才会真正的执行实际被代理的方法
joinPoint.proceed();
System.out.println("====>around finish ding");
}
}
用xml配置AOP
<?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.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 定义一个School类的Bean -->
<bean id="school1" class="io.simon.aop.School"/>
<!-- 定义一个Aop1类的Bean -->
<bean id="aop1" class="io.simon.aop.Aop1"/>
<aop:config>
<!-- 配置Aop的切点 -->
<!-- expression="execution(* io.simon.aop.InterfaceSchool.*(..))"
表示要执行io.simon.aop.InterfaceSchool类下面的所有方法-->
<aop:pointcut id="p1" expression="execution(* io.simon.aop.InterfaceSchool.*(..))"/>
<aop:aspect ref="aop1">
<aop:around method="around" pointcut-ref="p1"/>
<aop:before method="start" pointcut-ref="p1"/>
<aop:after method="end" pointcut-ref="p1"/>
</aop:aspect>
</aop:config>
</beans>
测试
package io.simon;
import io.simon.aop.InterfaceSchool;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("simonApplicationContext.xml");
InterfaceSchool school1 = context.getBean(InterfaceSchool.class);
school1.ding();
}
}
打印输出结果
注解配置AOP
被代理的接口InterfaceSchool
package io.simon.aop;
/**
* 被代理的接口
*/
public interface InterfaceSchool {
/**
* 铃声ding
*/
void ding();
}
该接口有一个实现类School
package io.simon.aop;
public class School implements InterfaceSchool {
@Override
public void ding() {
System.out.println("ding ....... 上课了");
}
}
在InterfaceSchool
接口的ding
方法上做增强。定义的AOP如下。
package io.simon.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect//将整个类声明为一个切面
public class Aop2 {
//将point()方法声明为一个切面,切在io.simon.aop.InterfaceSchool类的所有方法上面
@Pointcut(value = "execution(* io.simon.aop.InterfaceSchool.*(..))")
public void point() {
}
@Before(value = "point()")//将before方法绑定到point这个切面上
public void before() {
System.out.println("====>begin ding... ");
}
//将after方法绑定到point这个切面上
@AfterReturning(value = "point()")//AfterReturning方法在point方法return以后执行
public void before() {
public void end() {
System.out.println("====>finish ding... ");
}
//将around方法绑定到point这个切面上
@Around("point()")//around方法环绕着point方法执行,在before方法前,在after方法后
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("====>around begin ding");
joinPoint.proceed();
System.out.println("====>around finish ding");
}
}
xml中只需要bean相关的配置并开启AOP的注解支持
<?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.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 定义一个School类的Bean -->
<bean id="school2" class="io.simon.aop.School"/>
<bean id="aop2" class="io.simon.aop.Aop2"/>
<!-- Enables the use of the @AspectJ style of Spring AOP -->
<aop:aspectj-autoproxy/>
</beans>
测试
package io.simon;
import io.simon.aop.InterfaceSchool;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("simonApplicationContext.xml");
InterfaceSchool school2 = context.getBean(InterfaceSchool.class);
school2.ding();
}
}
运行结果
Spring Bean
Bean的整个加载过程
需要查看详细的代码,可以重点关注
org.springframework.beans.factory.support包下AbstractAutowireCapableBeanFactory类的
doCreateBean
和instantiateBean
方法。
关于Bean的配置,我们通常使用xml和注解这两种方式来进行配置。
使用xml来配置Bean
由于需要通过Setter方法来注入值,因此Student类中Setter方法是必须的,Getter方法可以不要。
Student类
package spring.beans;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data//自动生成Getter和Setter方法,还会生成ToString方法
public class Student {
private String name;
private String id;
private String school;
}
在resources文件夹下新建applicationContext.xml
配置文件
D:\dev\Java\java-traning\spring-learning>tree
卷 Data 的文件夹 PATH 列表
卷序列号为 5665-4A88
D:.
├─.idea
│ └─inspectionProfiles
├─src
│ ├─main
│ │ ├─java
│ │ │ └─spring
│ │ │ ├─aop
│ │ │ └─beans
│ │ └─resources
│ └─test
│ └─java
└─target
├─classes
│ └─spring
│ └─beans
└─generated-sources
└─annotations
在applicationContext.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.xsd">
<bean id="student01" class="spring.beans.Student">
<property name="name" value="张三"/>
<property name="id" value="20171060001"/>
<property name="school" value="北京大学"/>
</bean>
</beans>
测试类,从ClassPathXmlApplicationContext
中取出bean。
package spring.beans;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student01");
System.out.println(student.toString());
}
}
使用注解配置Bean
方法一:使用@Bean显示声明
Student类
package spring.beans;
import lombok.Data;
@AllArgsConstructor//有参构造方法是必需的
@ToString
public class Student {
private String name;
private String id;
private String school;
}
Student的配置类。
带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。
@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。
package spring.beans;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class StudentConf {
@Bean(name = "student02")
public Student student() {
return new Student("李四", "20171060002", "清华大学");
}
}
测试类:AnnotationConfigApplicationContext
指定含有bean的package。
package spring.beans;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext("spring.beans");
Student student = (Student) context.getBean("student02");
System.out.println(student.toString());
}
}
方法二:不使用@Bean显示声明
Student类如下:
使用@Component
,@Service
,@Controller
,@Repository
都能隐式地创建Bean。Student类中不需要有参构造方法,Setter方法也不需要。无参构造方法是默认就有的。
package spring.beans;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@ToString
@Component
//@Service
//@Controller
//@Repository
public class Student {
@Value("王五")
private String name;
@Value("20171060003")
private String id;
@Value("南京大学")
private String school;
}
测试类
package spring.beans;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {;
ApplicationContext context = new AnnotationConfigApplicationContext("spring.beans");
Student student = context.getBean(Student.class);
System.out.println(student.toString());
}
}
Spring XML配置原理
在xml的文件头部,会有很多链接,这些链接是xml文件的命名空间,规定了我们能在该文件中配置的内容。
所有的jar包里也会带上.xsd这个文件
在spring.schemas这个文件里指明了xsd位于jar包中的哪一个路径。
在xml中进行配置时,会出现提示,提示了我们能配置的属性,这便是xsd文件的作用。
如下内容便是spring-beans.xsd文件中所定义的一小部分。
xml中定义的Bean怎么转化为一个Bean的定义呢?这是根据spring.handles中指定的转换规则来进行转化的。
在spring.handles中对应的几个java类中,实现了读取xml的DOM节点,将其拼装为一个Bean的定义。然后再执行Spring Bean从创建到销毁的这整个流程。
总结起来,XML配置的整个流程如下:
而从Spring 2.5开始,就开始逐渐支持注解方式的配置,到现在注解的配置已经成为了主流方式。
标签:XML,ding,Spring,springframework,Bean,context,org,import,public 来源: https://blog.csdn.net/qq_42799615/article/details/113796722