<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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
beans>
<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.0modelVersion>
<groupId>com.southwindgroupId>
<artifactId>aispringiocartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.0.11.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>5.0.11.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.0.11.RELEASEversion>
dependency>
dependencies>
project>
传统程序开发,需要调用者创建被调用者的实例(对象由调用者new出来的)
而在Spring框架中,创建对象交由IoC容器完成推送给调用者
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private String name;
private int age;
}
在配置文件中设置IoC
<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="person" class="com.lin.entity.Person">
<property name="name" value="张三">property>
<property name="age" value="18">property>
bean>
beans>
<bean id="person1" class="com.lin.entity.Person">
<constructor-arg name="name" value="李四">constructor-arg>
<constructor-arg name="age" value="10">constructor-arg>
bean>
从IoC中获取对象
public class Test1 {
public static void main(String[] args) {
// 加载配置文件
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Person people = (Person)applicationContext.getBean("person");
System.out.println(people);
}
}
也可通过运行时类获取 bean,这种⽅式存在⼀个问题,配置⽂件中⼀个数据类型的对象只能有⼀个实例,否则会抛出异常,因为没有唯一的 bean
java Person people = applicationContext.getBean(Person.class);
name:成员变量名
value:成员变量(基本数据类型,String 可以直接赋值,如果是其他引用类型,不能通过 value 赋值)
ref :将 IoC 中的另外一个 < bean > 赋给当前的成员变量量(DI 依赖注入)
<bean id="person" class="com.lin.entity.Person">
<property name="name" value="张三">property>
<property name="age" value="18">property>
<property name="student" ref="student">property>
bean>
<bean id="student" class="com.lin.entity.Student">
<property name="name" value="小明">property>
<property name="id" value="1">property>
bean>
<bean id="person2" class="com.lin.entity.Person">
<property name="name" value="王五">property>
<property name="age" value="20">property>
<property name="student">
<list>
<ref bean="student1">ref>
<ref bean="student2">ref>
list>
property>
bean>
仿写:解析xml + 利用反射机制创建对象
public class ClassPathXmlApplicationContext implements ApplicationContext {
private Map<String,Object> map= new HashMap<String,Object>();
public ClassPathXmlApplicationContext(String path){
try {
// 利用DOM4j,读取xml文件
SAXReader reader = new SAXReader();
Document document = reader.read("./src/main/resources/"+path);
// 读取根节点
Element rootElement = document.getRootElement();
// 获取迭代器
Iterator<Element> iterator = rootElement.elementIterator();
while (iterator.hasNext()){
Element element = iterator.next();
// 获取id和class
String id = element.attributeValue("id");
String className = element.attributeValue("class");
// 通过反射创建对象
Class aClass = Class.forName(className);
// 获取构造方法,创建对象
Constructor constructor = aClass.getConstructor();
Object object = constructor.newInstance();
// 给对象赋值
Iterator<Element>beanIterator = element.elementIterator();
while (beanIterator.hasNext()){
Element property = beanIterator.next();
String name = property.attributeValue("name");
String valueStr = property.attributeValue("value");
// 获取set方法名称
String methodName= "set"+name.substring(0,1).toUpperCase()+name.substring(1);
// 得到set方法
Field field = aClass.getDeclaredField(name);
Method method = aClass.getDeclaredMethod(methodName, field.getType());
// 根据成员变量类型,转换value类型
Object value = null;
if (field.getType().getName()=="int"){
value = Integer.parseInt(valueStr);
}
if (field.getType().getName()=="java.lang.String"){
value = valueStr;
}
// 执行set方法,为成员变量赋值
method.invoke(object, value);
}
// 添加到map集合
map.put(id, object);
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
public Object getBean(String name) {
return map.get(name);
}
}
Spring 管理的 bean 是根据 scope 来生成的,表示 bean 的作用域,共4种,默认值是singleton。
request 和 session 只适用于 Web 项目,⼤多数情况下,使用单例和原型较多。
与 Java 的继承不同,Java 是类层面的继承,⼦类可以继承⽗父类的内部结构信息;Spring 是对象层⾯的继承,子对象可以继承父对象的属性值。
<bean id="people" class="com.lin.entity.Person" parent="person">
A依赖B,先创建B,再创建A
<bean id="A" class="com.lin.entity.Person" depends-on="B">bean>
IoC 通过工厂模式创建 bean 的方式有两种:
- 静态工厂方法:
public class StaticCarFactory {
private static Map<Integer, Car> carMap;
static {
carMap=new HashMap<Integer, Car>();
carMap.put(1, new Car(1, "大众"));
carMap.put(2, new Car(2, "宝马"));
}
public static Car getCar(Integer id){
return carMap.get(id);
}
}
<bean id="car" class="com.lin.factory.StaticCarFactory" factory-method="getCar">
<constructor-arg name="id" value="1">constructor-arg>
bean>
public class Test3 {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-factory.xml");
Car car1 =(Car) applicationContext.getBean("car1");
System.out.println(car1);
}
}
- 实例工厂方法
public class InstanceCarFactory {
private Map<Integer, Car> carMap;
public InstanceCarFactory(){
carMap=new HashMap<Integer, Car>();
carMap.put(1, new Car(1, "大众"));
carMap.put(2, new Car(2, "宝马"));
}
public Car getCar(Integer id){
return carMap.get(id);
}
}
<bean id="carFactory" class="com.lin.factory.InstanceCarFactory">bean>
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg name="id" value="2">constructor-arg>
bean>
public class Test4 {
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring-factory.xml");
Car car2 = (Car) applicationContext.getBean("car2");
System.out.println(car2);
}
}
IoC 负责创建对象,DI 负责完成对象的依赖注入,通过配置 property 标签的 ref 属性来完成,同时Spring 提供了另外一种更加简便的依赖注入方式:自动装载,不需要手动配置 property,IoC 容器器会⾃动选择 bean 完成注⼊入。
<bean id="person" class="com.lin.entity.Person" autowire="byName">bean>
<bean id="person" class="com.lin.entity.Person" autowire="byType">bean>
AOP:Aspect Oriented Programming ⾯向切面编程。
AOP 是对面向对象编程的⼀个补充,在运行时,动态地将代码切⼊到类的指定⽅法、指定位置上的编程思想就是⾯向切面编程。将不同⽅法的同⼀个位置抽象成⼀个切面对象,对该切面对象进行编程就是AOP。
降低模块之间的耦合度。
使系统更容易扩展。
更好的代码复用。
⾮业务代码更加集中,不分散,便于统⼀管理。
业务代码更加简洁纯粹,不参杂其他代码的影响。
动态代理:
动态代理类
public class ProxyFactory {
// 获取代理对象
public static Object getProxy(Object object){
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(object);
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),myInvocationHandler );
}
}
class MyInvocationHandler implements InvocationHandler {
// 委托对象
private Object object;
public MyInvocationHandler(Object object) {
this.object = object;
}
// 代理对象执行方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("正在执行"+method.getName()+"方法的参数为:"+ Arrays.toString(args));
// 委托对象执行方法
Object invoke = method.invoke(object, args);
System.out.println("结果为:"+invoke.toString());
return invoke;
}
}
接口的实现类
public class CalculateImpl implements Calculate{
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b){
return a-b;
}
}
测试
public class ProxyTest {
public static void main(String[] args) {
// 委托对象
Calculate calculate = new CalculateImpl();
// 代理对象
Calculate proxy = (Calculate) ProxyFactory.getProxy(calculate);
proxy.add(10, 5);
proxy.sub(10, 5);
}
}
Spring 框架对 AOP 进⾏行了封装,使⽤Spring 框架可以用面向对象的思想来实现 AOP。
Spring 框架中不需要创建 InvocationHandler,只需要创建一个切面对象,将所有的非业务代码在切面对象中完成即可,Spring 框架底层会自动根据切面类以及目标类⽣生成一个代理对象。
在切面类添加注解:
@Component :将给类的对象注入到 IoC 容器
@Aspect :表示是切面类
@Before :在执行业务代码前执行
@After :在执行业务代码后执行
@Aspect
@Component
public class LoggerAspect {
/**
*业务执行前操作
*/
@Before("execution(public int com.lin.aop.CalculateImpl.*(..))")
public void before(JoinPoint joinPoint){
// 获取方法名
String name = joinPoint.getSignature().getName();
// 获取参数
String args = Arrays.toString(joinPoint.getArgs());
System.out.println("正在执行"+name+"方法的参数为:"+ args);
}
/**
* 业务执行后操作
*/
@After("execution(public int com.lin.aop.CalculateImpl.*(..))")
public void after(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName()+"方法执行完毕");
}
/**
*对业务返回值进行操作
*/
@AfterReturning(value = "execution(public int com.lin.aop.CalculateImpl.*(..))",returning = "result")
public void afterReturning(Object result){
System.out.println("结果为"+result);
}
/**
*处理业务异常
*/
@AfterThrowing(value = "execution(public int com.lin.aop.CalculateImpl.*(..))",throwing = "exception")
public void afterThrowing(Exception exception){
System.out.println("异常为"+exception);
}
}
在业务方法也需要添加注解:
@Component
@Component
public class CalculateImpl implements Calculate {
public int add(int a, int b) {
return a + b;
}
public int sub(int a, int b) {
return a - b;
}
}
配置xml文件
<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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="com.lin">context:component-scan>
<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
beans>
context:component-scan
将 com.lin 包中的所有类进行扫描,如果该类添加了@Component ,则将该类扫描到 IoC 容器中,即 IoC 管理它的对象。
aop:aspectj-autoproxy
让 Spring 框架结合切面类和目标类自动生成动态代理对象。
测试
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop.xml");
Calculate calculate = (Calculate) context.getBean("calculateImpl");
calculate.add(10, 5);
calculate.sub(20, 10);
}
}
bean名称默认为业务类名首字母小写,也可以@Component(“XXX”)指定(相当于在xml文件中配置bean)