Spring注解驱动开发

IOC

组件注册-@Configuration&@Bean给容器中注册组件

在这里插入图片描述
修改pom文件

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.atguigu</groupId>
  <artifactId>spring-annotation</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <dependencies>
  	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-context</artifactId>
	    <version>4.3.12.RELEASE</version>
	</dependency>
  </dependencies>
</project>

如果
在这里插入图片描述

创建一个实体类

package com.atguigu.bean;

public class Person {
	private String name;
	private Integer age;
	
	public Person() {
		super();
	}
	
	public Person(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}

以前的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"
	xmlns:tx="http://www.springframework.org/schema/tx"
	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-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">


	<bean id="person" class="com.atguigu.bean.Person">
		<property name="age" value="18"></property>
		<property name="name" value="zhangsan"></property>
	</bean>
	

</beans>

package com.atguigu;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.atguigu.bean.Person;
import com.atguigu.config.MainConfig;

public class MainTest {

	@SuppressWarnings("resource")
	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
		Person person = (Person)applicationContext.getBean("person");
		System.out.println(person);
	}
}

@Bean注解方式

package com.atguigu.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.atguigu.bean.Person;

/**
 * 配置类
 * 等同于以前的配置文件
 */
@Configuration  //告诉Spring这是一个配置类
public class MainConfig {
	
	//给容器中注册一个Bean,类型为返回值的类型,id默认是用方法名作为id  
	@Bean
	public Person person() {
		return new Person("lisi",20);
	}
	
}

package com.atguigu;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.atguigu.bean.Person;
import com.atguigu.config.MainConfig;

public class MainTest {

	public static void main(String[] args) {
//		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//		Person person = (Person)applicationContext.getBean("person");
//		System.out.println(person);
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
		Person person = applicationContext.getBean(Person.class);
		System.out.println(person);
	}
	
}

@Bean(“person02”) 还可以为Bean的类型名取名

组件注册-@ComponentScan-自动扫描组件&指定扫描规则

以前的xml扫描

<!-- 包扫描、只要标注了@Controller@Service@Repository@Component -->
	<context:component-scan base-package="com.atguigu"></context:component-scan>

等同于注解

@ComponentScan(value = "com.atguigu"

BookController

package com.atguigu.controller;

import org.springframework.stereotype.Controller;

@Controller
public class BookController {

}

BookDao

package com.atguigu.dao;

import org.springframework.stereotype.Repository;

@Repository
public class BookDao {

}

BookService

package com.atguigu.service;

import org.springframework.stereotype.Service;

@Service
public class BookService {

}

MainConfig

package com.atguigu.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

import com.atguigu.bean.Person;

/**
 * 配置类
 * 等同于以前的配置文件
 */
@Configuration  //告诉Spring这是一个配置类
@ComponentScan(value = "com.atguigu")
public class MainConfig {
	
	//给容器中注册一个Bean,类型为返回值的类型,id默认是用方法名作为id  
	@Bean
	public Person person() {
		return new Person("lisi",20);
	}
	
}

IOCTest

package com.atguigu.test;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.atguigu.config.MainConfig;

public class IOCTest {
	
	
	@SuppressWarnings("resource")
	@Test
	public void test01() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
		String[] definitionNames = applicationContext.getBeanDefinitionNames();
		for (String name : definitionNames) {
			System.out.println(name);
		}
	}
}

在这里插入图片描述

@ComponentScan

在这里插入图片描述

  • includeFilters: 只扫描哪些
  • excludeFilters: 排除哪些
excludeFilters

在这里插入图片描述

  • ANNOTATION:按注解排除
  • ASPECTJ:按ASPECTJ表达式排除
  • ASSIGNABLE_TYPE: 按类型排除
  • CUSTOM: 按自定义排除
  • REGEX: 按正则表达式排除

例如使用ANNOTATION

package com.atguigu.config;

import java.security.Provider.Service;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

import com.atguigu.bean.Person;

/**
 * 配置类
 * 等同于以前的配置文件
 */
@Configuration  //告诉Spring这是一个配置类
@ComponentScan(value = "com.atguigu",excludeFilters = {
		@Filter(type=FilterType.ANNOTATION,classes={Controller.class,Service.class})
})
public class MainConfig {
	
	//给容器中注册一个Bean,类型为返回值的类型,id默认是用方法名作为id  
	@Bean
	public Person person() {
		return new Person("lisi",20);
	}
	
}

在这里插入图片描述

includeFilters

以前在xml中必须配置禁用默认的过滤规则

	<!-- 包扫描、只要标注了@Controller@Service@Repository@Component -->
	<context:component-scan base-package="com.atguigu" use-default-filters="false"></context:component-scan>

注解
useDefaultFilters = false

package com.atguigu.config;

import java.security.Provider.Service;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

import com.atguigu.bean.Person;

/**
 * 配置类
 * 等同于以前的配置文件
 */
@Configuration  //告诉Spring这是一个配置类
@ComponentScan(value = "com.atguigu",includeFilters = {
		@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
},useDefaultFilters = false)
public class MainConfig {
	
	//给容器中注册一个Bean,类型为返回值的类型,id默认是用方法名作为id  
	@Bean
	public Person person() {
		return new Person("lisi",20);
	}
	
}

在这里插入图片描述
只有controller

@ComponentScan是重复注解,可以多次使用,或者使用@ComponentScans

@ComponentScans(
	value = {@ComponentScan(value = "com.atguigu",includeFilters = {
			@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
	},useDefaultFilters = false)
	}
)
FilterType.ASSIGNABLE_TYPE
@ComponentScans(
	value = {@ComponentScan(value = "com.atguigu",includeFilters = {
			@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
			@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class})
	},useDefaultFilters = false)
	}
)

在这里插入图片描述

FilterType.CUSTOM
@ComponentScans(
	value = {@ComponentScan(value = "com.atguigu",includeFilters = {
			@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
	},useDefaultFilters = false)
	}
)
package com.atguigu.config;

import java.io.IOException;

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

public class MyTypeFilter implements TypeFilter {

	/**
	 * metadataReader:读取到的当前正在扫描的类的信息
	 * metadataReaderFactory:不止当前类,可以获取到其他任何类信息
	 */
	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		//获取当前类注解的信息
		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		//获取当前正在扫描的类的类信息
		ClassMetadata classMetadata = metadataReader.getClassMetadata();
		//获取当前类资源(例如类的路径)
		Resource resource = metadataReader.getResource();
		
		//类名
		String className = classMetadata.getClassName();
		System.out.println("--->"+className);
		
		return false;
	}

}

只要当前处理到哪个类,类的信息都可以获取的到
在这里插入图片描述
获取到这些类的信息,我们就可以做判断,满足条件的返回true.

package com.atguigu.config;

import java.io.IOException;

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

public class MyTypeFilter implements TypeFilter {

	/**
	 * metadataReader:读取到的当前正在扫描的类的信息
	 * metadataReaderFactory:不止当前类,可以获取到其他任何类信息
	 */
	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		//获取当前类注解的信息
		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		//获取当前正在扫描的类的类信息
		ClassMetadata classMetadata = metadataReader.getClassMetadata();
		//获取当前类资源(例如类的路径)
		Resource resource = metadataReader.getResource();
		
		//类名
		String className = classMetadata.getClassName();
		System.out.println("--->"+className);
		
		//指定一个规则
		if(className.contains("er")) {
			return true;
		}
		return false;
	}

}

这些都包含er
在这里插入图片描述

组件注册-@Scope-设置组件作用域

package com.atguigu.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.atguigu.bean.Person;

@Configuration
public class MainConfig2 {

	
	@Bean("person")
	public Person person() {
		return new Person("张三",25);
	}
	
}

package com.atguigu.test;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.atguigu.config.MainConfig2;

public class IOCTest {
	
	
	@SuppressWarnings("resource")
	@Test
	public void test01() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
		String[] definitionNames = applicationContext.getBeanDefinitionNames();
		for (String name : definitionNames) {
			System.out.println(name);
		}
		
		Object bean = applicationContext.getBean("person");
		Object bean2 = applicationContext.getBean("person");
		//输出一下,两个对象是否相等
		System.out.println(bean == bean2);
	}
}

是相等的,默认是单实例。
在这里插入图片描述

@Scope

参数:

  • prototype: 多实例的、ioc容器启动不会调用方法创建对象,每次获取的时候才会调用方法创建对象。
  • singleton: 单实例的(默认值)、ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从容器(map.get())中拿。
  • request: 同一次请求创建一个实例
  • session: 同一个session创建一个实例
package com.atguigu.config;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

import com.atguigu.bean.Person;

@Configuration
public class MainConfig2 {

	//默认是单实例的
	/**
	 * ConfigurableBeanFactory#SCOPE_PROTOTYPE   prototype
	 * ConfigurableBeanFactory#SCOPE_SINGLETON   singleton
	 * org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST   request
	 * org.springframework.web.context.WebApplicationContext#SCOPE_SESSION   session
	 * 
	 * prototype: 多实例的
	 * singleton: 单实例的(默认值)
	 * request: 同一次请求创建一个实例
	 * session: 同一个session创建一个实例
	 * @return
	 */
	@Scope("prototype")
	@Bean("person")
	public Person person() {
		return new Person("张三",25);
	}
	
}

在这里插入图片描述

组件注册-@Lazy-bean懒加载

懒加载:

  • 单实例bean:默认在容器启动的时候创建对象;
  • 懒加载:容器启动不创建对象。第一次使用(获取)bean创建对象,并初始化。只会创建一次。
package com.atguigu.config;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

import com.atguigu.bean.Person;

@Configuration
public class MainConfig2 {

	//默认是单实例的
	/**
	 * @Scope
	 * ConfigurableBeanFactory#SCOPE_PROTOTYPE   prototype
	 * ConfigurableBeanFactory#SCOPE_SINGLETON   singleton
	 * org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST   request
	 * org.springframework.web.context.WebApplicationContext#SCOPE_SESSION   session
	 * prototype: 多实例的
	 * singleton: 单实例的(默认值)
	 * request: 同一次请求创建一个实例
	 * session: 同一个session创建一个实例
	 * 
	 * @return
	 * 
	 * @Lazy懒加载
	 */
	@Lazy
	@Bean("person")
	public Person person() {
		return new Person("张三",25);
	}
	
}

组件注册-@Conditional-按照条件注册bean

@Conditional({Condition}): 按照一定的条件进行判断,满足条件给容器中注册bean

package com.atguigu.config;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

import com.atguigu.bean.Person;
import com.atguigu.condition.LinuxCondition;
import com.atguigu.condition.WindowsCondition;

@Configuration
public class MainConfig2 {


	
	
	/**
	 * @Conditional({Condition}): 按照一定的条件进行判断,满足条件给容器中注册bean
	 * 
	 * 如果系统是windows ,给容器中注册("bill")
	 * 如果系统是linux ,给容器中注册("linux")
	 */
	@Conditional({WindowsCondition.class})
	@Bean("bill")
	public Person person01() {
		return new Person("Bill Gates",62);
	}
	
	@Conditional({LinuxCondition.class})
	@Bean("linux")
	public Person person02() {
		return new Person("linux",48);
	}
}

@Conditional需要Condition类来判断

WindowsCondition
package com.atguigu.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

//判断系统是否是Windows
public class WindowsCondition implements Condition{
	

	


	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// 是否Windows系统
		
		//1.能获取到ioc使用的beanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//2.获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		//3.获取当前环境信息
		Environment environment = context.getEnvironment();
		//4.获取到bean定义的注册类
		BeanDefinitionRegistry registry = context.getRegistry();
		
		String property = environment.getProperty("os.name");
		if(property.contains("Windows")) {
			return true;
		}
			
		return false;
	}
	

}

LinuxCondition
package com.atguigu.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

//判断系统是否是Linux 
public class LinuxCondition implements Condition{

	/**
	 * ConditionContext: 判断条件能使用的上下文环境
	 * AnnotatedTypeMetadata: 注释信息
	 */
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// 是否linux系统
		
		//1.能获取到ioc使用的beanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//2.获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		//3.获取当前环境信息
		Environment environment = context.getEnvironment();
		//4.获取到bean定义的注册类
		BeanDefinitionRegistry registry = context.getRegistry();
		
		String property = environment.getProperty("os.name");
		if(property.contains("linux")) {
			return true;
		}
		return false;
	}
}
测试
package com.atguigu.test;

import java.util.Map;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import com.atguigu.bean.Person;
import com.atguigu.config.MainConfig2;

public class IOCTest {
	
	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);

	@Test
	public void test01() {
		
		String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
		ConfigurableEnvironment environment = applicationContext.getEnvironment();
		//动态获取环境变量的值
		String property = environment.getProperty("os.name");
		System.out.println(property);
		for (String name : beanNamesForType) {
			System.out.println(name);
		}

		Map<String, Person> persons = applicationContext.getBeansOfType(Person.class);
		System.out.println(persons);
		
	}
}

在这里插入图片描述
再试试Linux,当然我不可能切换操作系统
我们改变一个运行时变量。
在这里插入图片描述
在这里插入图片描述
不仅可以加在方法上 ,也可以加在类上。

组件注册-@Import-给容器中快速导入一个组件

给容器中注册组件

  • 包扫描+组件标注注解(@Controller/@Service/Repository/@Component)
  • @Bean[导入的第三方包里面的组件]
  • @Import[快速给容器中导入一个组件]

@Import(要导入到容器中的组件)

容器中就会自动注册这个组件,id默认是全类名

导入组件,id默认是组件的全类名
package com.atguigu.bean;

public class Color {

}

package com.atguigu.bean;

public class Red {

}

package com.atguigu.config;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

import com.atguigu.bean.Color;
import com.atguigu.bean.Person;
import com.atguigu.bean.Red;
import com.atguigu.condition.LinuxCondition;
import com.atguigu.condition.WindowsCondition;

@Configuration
@Import(Color.class) //导入组件,id默认是组件的全类名
public class MainConfig2 {


}

package com.atguigu.test;

import java.util.Map;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import com.atguigu.bean.Person;
import com.atguigu.config.MainConfig2;

public class IOCTest {
	
	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);

	@Test
	public void testImport() {
		printBeans(applicationContext); 
	}
	
	private void printBeans(AnnotationConfigApplicationContext applicationContext) {
		String[] definitionNames = applicationContext.getBeanDefinitionNames();
		for (String name : definitionNames) {
			System.out.println(name);
		}
	}
	
	
}

在这里插入图片描述

导入多个组件
package com.atguigu.config;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

import com.atguigu.bean.Color;
import com.atguigu.bean.Person;
import com.atguigu.bean.Red;
import com.atguigu.condition.LinuxCondition;
import com.atguigu.condition.WindowsCondition;

@Configuration
//@Import(Color.class) //导入组件,id默认是组件的全类名
@Import({Color.class,Red.class})  //导入多个组件
public class MainConfig2 {


	

}

在这里插入图片描述

组件注册-@Import-使用ImportSelector

ImportSelector: 返回需要导入的组件的全类名数组

package com.atguigu.bean;

public class Blue {

}

package com.atguigu.bean;

public class Yellow {

}

package com.atguigu.condition;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector{

	//返回值,就是要导入到容器中的组件全类名
	//AnnotationMetadata: 当前标注@Import注解的类的所有注解信息
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		// TODO Auto-generated method stub
//		importingClassMetadata.get //可以获取了所有注解的信息和所有跟类有关的信息
		//不要返回null值,可以返回空数组new String[]{};
		return new String[] {"com.atguigu.bean.Blue","com.atguigu.bean.Yellow"};
	}

}

package com.atguigu.config;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

import com.atguigu.bean.Color;
import com.atguigu.bean.Person;
import com.atguigu.bean.Red;
import com.atguigu.condition.LinuxCondition;
import com.atguigu.condition.MyImportSelector;
import com.atguigu.condition.WindowsCondition;

@Configuration
//@Import(Color.class) //导入组件,id默认是组件的全类名
@Import({Color.class,Red.class,MyImportSelector.class})  //导入多个组件
public class MainConfig2 {


	

}

package com.atguigu.test;

import java.util.Map;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import com.atguigu.bean.Person;
import com.atguigu.config.MainConfig2;

public class IOCTest {
	
	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);

	@Test
	public void testImport() {
		printBeans(applicationContext); 
	}
	
	private void printBeans(AnnotationConfigApplicationContext applicationContext) {
		String[] definitionNames = applicationContext.getBeanDefinitionNames();
		for (String name : definitionNames) {
			System.out.println(name);
		}
	}
	
	
}

在这里插入图片描述

组件注册-@Import-使用ImportBeanDefinitionRegistrar

package com.atguigu.condition;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

import com.atguigu.bean.RainBow;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar{

	/**
	 * AnnotationMetadata: 当前类的注解信息以及其他的信息
	 * BeanDefinitionRegistry: BeanDefinition注册类
	 * 		把所有中需要添加到容器中的bean;
	 * 		BeanDefinitionRegistry.registerBeanDefinition(手动注册进来)
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		
		boolean definition = registry.containsBeanDefinition("com.atguigu.bean.Red");
		boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue");
		if(definition && definition2) {
			//指定bean名
			RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class);
			registry.registerBeanDefinition("rainBow", rootBeanDefinition);
		}
	}

}

package com.atguigu.config;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

import com.atguigu.bean.Color;
import com.atguigu.bean.Person;
import com.atguigu.bean.Red;
import com.atguigu.condition.LinuxCondition;
import com.atguigu.condition.MyImportBeanDefinitionRegistrar;
import com.atguigu.condition.MyImportSelector;
import com.atguigu.condition.WindowsCondition;

@Configuration
//@Import(Color.class) //导入组件,id默认是组件的全类名
@Import({Color.class,Red.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})  //导入多个组件
public class MainConfig2 {


	

}

package com.atguigu.test;

import java.util.Map;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import com.atguigu.bean.Person;
import com.atguigu.config.MainConfig2;

public class IOCTest {
	
	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);

	@Test
	public void testImport() {
		printBeans(applicationContext); 
	}
	
	private void printBeans(AnnotationConfigApplicationContext applicationContext) {
		String[] definitionNames = applicationContext.getBeanDefinitionNames();
		for (String name : definitionNames) {
			System.out.println(name);
		}
	}
	
	
}

在这里插入图片描述

组件注册-使用FactoryBean注册组件

package com.atguigu.bean;

import org.springframework.beans.factory.FactoryBean;

//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color>{

	//返回一个Color对象,这个对象会添加到容器中
	@Override
	public Color getObject() throws Exception {

		System.out.println("ColorFactoryBean...getgetObject....");
		return new Color();
	}

	@Override
	public Class<?> getObjectType() {
		System.out.println("ColorFactoryBean...getObjectType....");
		return Color.class;
	}

	//控制是否是单例
	//true:这个bean是单实例,在容器中保存一份
	//false: 多实例,每次获取都会创建一个新的bean
	@Override
	public boolean isSingleton() {
		// TODO Auto-generated method stub
		return true;
	}

}

package com.atguigu.config;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

import com.atguigu.bean.Color;
import com.atguigu.bean.ColorFactoryBean;
import com.atguigu.bean.Person;
import com.atguigu.bean.Red;
import com.atguigu.condition.LinuxCondition;
import com.atguigu.condition.MyImportBeanDefinitionRegistrar;
import com.atguigu.condition.MyImportSelector;
import com.atguigu.condition.WindowsCondition;

@Configuration
//@Import(Color.class) //导入组件,id默认是组件的全类名
@Import({Color.class,Red.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})  //导入多个组件
public class MainConfig2 {

	@Bean 
	public ColorFactoryBean colorFactoryBean() {
		return new ColorFactoryBean();
	}

}

package com.atguigu.test;

import java.util.Map;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import com.atguigu.bean.Person;
import com.atguigu.config.MainConfig2;

public class IOCTest {
	
	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);

	@Test
	public void testImport() {
		printBeans(applicationContext); 
	}
	
	private void printBeans(AnnotationConfigApplicationContext applicationContext) {
		String[] definitionNames = applicationContext.getBeanDefinitionNames();
		for (String name : definitionNames) {
			System.out.println(name);
		}
		
		Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
		Object colorFactoryBean2 = applicationContext.getBean("colorFactoryBean");
		System.out.println("colorFactoryBean的类型:"+colorFactoryBean.getClass());
		System.out.println(colorFactoryBean == colorFactoryBean2);
		//通过在前面加上& Spring就知道我们是需要工厂bean的本身
		Object colorFactoryBean3 = applicationContext.getBean("&colorFactoryBean");
		System.out.println("&colorFactoryBean的类型:"+colorFactoryBean3.getClass());

	}
	
	
}

在这里插入图片描述

AOP

AOP

  • 【动态代理】

指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;

导入aop模块;Spring AOP

在这里插入图片描述

定义一个业务逻辑类(MathCalculator)

package com.atguigu.aop;

/**
 * 数学计算器
 * @author john
 *
 */
public class MathCalculator {

	//除法
	public int div(int i,int j) {
		System.out.println("MathCalculator..........div");
		return i/j;
	}
	
}

我们需要在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常)

日志切面类(LogAspects)

切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行

通知方法:

  • 前置通知(@Before):logStart: 在目标方法(div)运行之前运行
  • 后置通知(@After):logEnd: 在目标方法(div)运行结束之后运行
  • 返回通知(@AfterReturning):logReturn: 在目标方法div正常返回之后运行
  • 异常通知(@AfterThrowing):logException: 在目标方法(div)出现异常以后运行
  • 环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
给切面类的目标方法标注何时何地运行(通知注解)

并且必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)

package com.atguigu.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * 切面类
 * 
 * @Aspect: 告诉Spring当前类是一个切面类
 * @author john
 *
 */
@Aspect
public class LogAspects {
	
	//抽取公共的切入点表达式
	//1.如果在本类引用:("pointCut()")
	//2.如果引用其他的切面类:必须用方法全名("com.atguigu.aop.LogAspects.pointCut()")
	//写法参照Spring官方文档
	@Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
	public void pointCut() {}
	
	//@Before:在目标方法之前切入 ; 切入点表达式(指定在哪个方法切入)
	//使用目标方法全名
//	@Before("public int com.atguigu.aop.MathCalculator.div(int, int)")
	//任意方法,任意多参数
//	@Before("public int com.atguigu.aop.MathCalculator.*(..)")
	//抽取公共的切入点表达式
	@Before("pointCut()")
	public void logStart(JoinPoint joinPoint) {
		//获取的方法的方法名: joinPoint.getSignature().getName()
		//获取的方法的参数: joinPoint.getArgs()
		Object[] args = joinPoint.getArgs();
		System.out.println(""+joinPoint.getSignature().getName()+"运行。。。参数列表是:{"+Arrays.asList(args)+"}");
	}
	
	//@After: 在目标方法之后;切入无论方法正常结束或者异常结束都执行
//	@After("public int com.atguigu.aop.MathCalculator.*(..)")
	//抽取公共的切入点表达式
	@After("pointCut()")
	public void logEnd(JoinPoint joinPoint) {
		System.out.println(""+joinPoint.getSignature().getName()+"结束");
	}
	
	//JoinPoint一定要出现在参数表的第一位
	@AfterReturning(value="pointCut()",returning="result")
	public void logReturn(JoinPoint joinPoint,Object result){
		System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
	}
	
	@AfterThrowing(value="pointCut()",throwing="exception")
	public void logException(JoinPoint joinPoint,Exception exception){
		System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
	}
}

配置类:将切面类和业务逻辑类(目标方法所在类)都加入到容器中

并且给配置类中加@EnableAspectJAutoProxy 【开启基于注解的aop模式】

package com.atguigu.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import com.atguigu.aop.LogAspects;
import com.atguigu.aop.MathCalculator;

/**
 * AOP:【动态代理】
 * 		指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;
 * 1、导入aop模块;Spring AOP :(spring-aspects)
 * 2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常)
 * 3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行;
 * 		通知方法:
 * 			前置通知(@Before):logStart: 在目标方法(div)运行之前运行
 * 			后置通知(@After):logEnd: 在目标方法(div)运行结束之后运行
 * 			返回通知(@AfterReturning):logReturn: 在目标方法div正常返回之后运行
 * 			异常通知(@AfterThrowing):logException: 在目标方法(div)出现异常以后运行
 * 			环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
 * 4、给切面类的目标方法标注何时何地运行(通知注解);并且必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)
 * 5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
 * 6、给配置类中加@EnableAspectJAutoProxy 【开启基于注解的aop模式】
 * 			在
 */
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {

	//业务逻辑类加入容器中
	@Bean
	public MathCalculator calculator() {
		return new MathCalculator();
	}
	
	//切面类加入到容器中
	@Bean
	public LogAspects logAspects() {
		return new LogAspects();
	}
	
}

测试类

package com.atguigu.test;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.atguigu.aop.MathCalculator;
import com.atguigu.config.MainConfigOfAOP;

import com.atguigu.dao.BookDao;
import com.atguigu.service.BookService;

public class IOCTest_AOP {
	
	@Test
	public void test01(){
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
		
		//1、不要自己创建对象
//		MathCalculator mathCalculator = new MathCalculator();
//		mathCalculator.div(1, 1);
		MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
		
		
		System.out.println("-----------------------正常测试------------------------");
		//正常测试
		mathCalculator.div(1, 1);
		
		System.out.println("-----------------------异常测试------------------------");
		//异常测试
		mathCalculator.div(1, 0);
		
		applicationContext.close();
	}

}

在这里插入图片描述
写AOP主要把握三步:

  • 1)、将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)
  • 2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
  • 3)、开启基于注解的aop模式 : @EnableAspectJAutoProxy
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值