Spring两大核心IOC容器、AOP的使用及总结

Spring两大核心IOC容器、AOP的使用及总结

​ Spring框架体系中核心就是IOC容器,IOC容器中文直译为控制反转,顾名思义也就是将组件的控制权交给IOC容器,IOC容器负责管理各个Bean的创建、装配和他的生命周期。AOP是面向切面的编程,OOP最大的特点就是封装、继承和多态,而AOP的最大用处就是让业务类专注的处理业务,其他琐事例如事务检查、验证和拦截等等交给切面去处理。这样说起来云里雾里的,下面让我们从一个简单的登录来介绍IOC和AOP的使用吧。

Spring核心IOC容器的使用

1)IOC原理

image

​ 我们在使用登录的时候需要验证密码,从而我们需要在LoginService中new一个DataSource的实例,在使用完之后我们得按顺序销毁这些对象,而我们使用Spring之后我们就可以单独的配置DataSource的Bean然后通过依赖注入的方式在LoginService使用,使用完之后容器会自动销毁这些实例对象不需要我们来过多的关注。

2)使用XML配置来装配Bean

​ 使用XML来装配Bean虽然要编写负责的xml配置文件但他的好处就是各种依赖的关系清晰明了。我们需要引入如下jar包

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    
    <dependency>
	    <groupId>com.zaxxer</groupId>
	    <artifactId>HikariCP</artifactId>
	    <version>2.7.1</version>
	</dependency>
	
	<dependency>
	    <groupId>mysql</groupId>
	    <artifactId>mysql-connector-java</artifactId>
	    <version>5.1.46</version>
	</dependency>

​ 其中HikariCP是一个连接池的jar包,使用的时候非常简单,只要配置好数据库信息,然后从DataSource中获取连接就行了。我们创建一个LoginService类再通过配置XML的方式注入需要再XML编写

<bean id = "dataSource" class = "com.zaxxer.hikari.HikariDataSource">
	<property name="jdbcUrl" value = "jdbc:mysql://localhost:3306/test"/>
	<property name="username" value="root"/>
	<property name="password" value="root" />
	<property name="maximumPoolSize" value="10" />
	<property name="autoCommit" value="true" />
</bean>
<bean id="loginService" class="Context.LoginService">
	<property name="dataSource" ref="dataSource"></property>
</bean>

​ 在LoginService中注入DataSource的方法有两种,一种就是编写setDataSource的方法,还有一种是编写构造方法直接注入。在此就不做过多的赘述。我们在使用的时候只要获取Context即应用程序的上下文来获取Bean,当然要在这个主程序的方法上来指定XML

	ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
	LoginService loginService = (LoginService) context.getBean("loginService");
	loginService.login("hezhihui", "handsome");

以上就是使用XML来实现Bean的装配和使用了。

3)使用注解的方式装配注入

​ 在上一小节中介绍了配置XML来装配Bean,但是这样有个缺点就是每增加一种依赖就必须来维护XML的配置,所以我们引入了注解的方式来注入,很简单我们把自己写的业务类组件加上注解@Component然后就可以在其他的组件通过@Autowired注入这些主键,重点来了例如DataSource类你总不能进去源码来给他加上注解把,所以我们在主程序入口加上@Configuration来标记配置入口,加上@ComponentScan来扫描所在包和子包下面的所有组件,我们在这个用Configuration注解标记的类下面来自定义Bean。自定义的Bean下面可以通过返回值的类型来进行依赖注入,具体代码如下

@Configuration
@ComponentScan
public class Main {
@Bean
DataSource createDataSource() {
	HikariConfig config = new HikariConfig();
	config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
	config.setUsername("root");
	config.setPassword("root");
	config.setAutoCommit(true);
	config.setMaximumPoolSize(10);
	DataSource ds = new HikariDataSource(config);
	return ds;
}

public static void main(String[] args) throws SQLException {
	ApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
	LoginService loginService = (LoginService) context.getBean(LoginService.class);
	loginService.login("hezhihui", "handsome");
}
}

​ 但是有个问题就随之被牵引而出,就是有多个相同的返回值的Bean可怎么办呢?比如有多个数据池分别用于测试,开发,生产环境下,当然是给Bean注解加上Value啦,@Bean(name = “xxx”)我们在依赖注入的时候就可以通过这个值来选择可注入的依赖

@Autowired(required = false)
@Qualifier("xxx")
private DataSource dataSource

​ 其实在真实的使用下是通过条件装配来实现不同环境下对数据源的切换,在Bean上添加注解下加上@Profile(“xxx”)我们在运行程序的时候只需要加上JVM参数-Dspring.profiles.active=xxx就可以指定以xxx环境启动。还有@Conditional注解根据返回值的Value来决定是否创建Bean,在此就不给出详细的代码了,可以去百度查看专业的文档。

AOP切面

1)AOP原理

​ AOP是用来处理一些非业务逻辑但又避免不了的操作,比如事务检查、性能监控等等。他的原理是Proxy代理模式的原理创建目标类的子类并传入原始实例和切面处理类。注:不会初始化原始实例的字段,所以要被代理的类不要用public final修饰,被代理的类尽量使用get和set方法来设置字段值。 其实这些东西只要理解了思想基本上都能手撸出来一个框架,其中注解的使用要比较熟练。

2)AOP拦截器的使用

​ 以下是常用拦截器的说明:

​ @Before:这种拦截器先执行拦截代码,再执行目标代码。如果拦截器抛异常,那么目标代码就不执行了;

​ @After:这种拦截器先执行目标代码,再执行拦截器代码。无论目标代码是否抛异常,拦截器代码都会执行;

​ @AfterReturning:和@After不同的是,只有当目标代码正常返回时,才执行拦截器代码;

​ @AfterThrowing:和@After不同的是,只有当目标代码抛出了异常时,才执行拦截器代码;

​ @Around:能完全控制目标代码是否执行,并可以在执行前后、抛异常后执行任意拦截代码,可以说是包含了上面所有功能。

​ 拦截器的使用是实现一个类并加上组件的注解以及切面的注解,然后通过拦截器声明拦截的路径。并进行对原始的实例处理。代码示范如下:

@Aspect
@Component
public class CheakAspect {
	@Before("execution(public * LoginService.*(..))")
	public void doCheck() {
		System.out.println("docheck now");
	}
	@Around("execution(public * LoginService.*(..))")
	public Object sss(ProceedingJoinPoint pjp) throws Throwable {
		Object ss = pjp.proceed();
		System.out.println("结束啦");
		return ss;
	}
}

​ 这个拦截路径还是比较难编写的,过于复杂还容易出错,并且容易误杀(即拦截不该拦截的东西)。

3)使用自定义注解来实现AOP

​ 先自定义一个注解,然后在方法或者类前面加上注解,在切面的时候声明路径的时候把注解添加进去,所有加上注解的方法都会被拦截具体的代码如下:

//自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckRight {
	 String value();
}

//切面
@Aspect
@Component
public class CheakAspect {
	@Before("@annotation(CheckRight)")
	public void doCheck() {
		System.out.println("docheck now");
	}
}

​ 以上就是对IOC容器和AOP切面的使用总结啦,这里并不是教程所以很多地方都省略了代码和步骤,只说明了核心部分。大家以可以一起尝试着手撸一个切面处理。

posted @ 2022-11-11 14:31  迷糊桃  阅读(371)  评论(0编辑  收藏  举报