五.AOP

代理的类型分为两种,一种为静态代理,一种为动态代理。代理的目的是为了在切面上扩展业务,而不用改变原来的功能模块,具有很高的延伸性,但是代码量会增加两倍甚至更多。

1.静态代理

    静态代理如下代码所示:

interface Shopping {
    void buy();
}

class Client implements Shopping {
    public void buy() {
        System.out.println("我想买这件商品");
    }
}

class StaticProxy implements Shopping {
    private Shopping shopping;

    public StaticProxy(Shopping shopping) {
        this.shopping = shopping;
    }

    public void buy() {
        System.out.println("降价促销,疯狂大甩卖了!");
        shopping.buy();
    }
}

public class StaticProxyTest {
    public static void main(String[] args) {
        Client client = new Client();
        StaticProxy service = new StaticProxy(client);
        service.buy();
    }
}

2.动态代理

    动态代理需要通过创建继承了InvocationHandler接口的类,通过使用这个类,来创建代理,该类的代码如下:

package AOP;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHandler implements InvocationHandler{

	private Object target;
	
	public void setTarget(Object target)
	{
		this.target=target;
	}
	
	public Object getProxy()
	{
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		Object result=method.invoke(target, args);
		return result;
	}
     
}

该类使用到了两个特征明显的方法,分别是Proxy.newProxyInstance()和method.invoke().

其中Proxy.newProxyInstance()有三个传递参数,分别为:

1.loader:该类加载器

2.interface:目标类实现的接口

3.invocationHadler:该处理器

关于Invoke方法,相当于省略了静态代理时还要重写的方法,用到了JAVA的反射机制。具体的内容看:

JAVA的Invoke方法_JACKEYLLLLLOVE的博客-优快云博客

3.SpringAOP的配置文件

在使用AOP之前要引入一个aspectjweaver包,暂时不知道干什么的。

相应地址https://mvnrepository.com/

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

</beans>

4.SpringAOP的基本信息

相应信息如下:

SpringAOP,通过Advice定义横切逻辑,Spring中支持五种类型的Advice.

 即Aop在不改变原有代码的情况下,去增加新的功能。

5.使用Spring实现AOP

实例类:

package SpringAop;

import org.springframework.stereotype.Component;

@Component
public class UserServiceImp implements UserService{

	@Override
	public void add() {
		// TODO Auto-generated method stub
		System.out.println("添加了一个用户");
	}

	@Override
	public void delete() {
		// TODO Auto-generated method stub
		System.out.println("删除了一个用户");
	}

	@Override
	public void update() {
		// TODO Auto-generated method stub
		System.out.println("更新了信息");
	}

	@Override
	public void select() {
		// TODO Auto-generated method stub
		System.out.println("选择了一个用户");
	}

}

 方式一:使用Spring的接口。

相关日志类代码如下:

package SpringAop;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;

@Component
public class Log implements MethodBeforeAdvice{

	@Override
	//method:要执行的目标对象的方法
	//args:参数
	//target:目标对象
	public void before(Method method, Object[] args, Object target) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
	}

}
package SpringAop;
import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.stereotype.Component;

@Component
public class AfterLog implements AfterReturningAdvice{

	@Override
	//returnValue:返回值
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("执行了"+method.getName()+"方法.返回结果为"+returnValue);
	}

}

配置文件如下:

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
 
  <!-- 使用注释<context:component-scan base-package="SpringAop"/> -->
    <bean id="log" class="SpringAop.Log"></bean>
    <bean id="afterLog" class="SpringAop.AfterLog"></bean>
    <bean id="userService" class="SpringAop.UserServiceImp"></bean>
     
     <!-- 方式一:使用Spring原生的API -->   
     <!-- 配置AOP -->
    <aop:config>
       <!-- 切入点:expression:表达式;execution():要执行的位置:-->
       <aop:pointcut id="point" expression="execution(* SpringAop.UserServiceImp.*(..))"/>
       <!-- 执行环绕 -->
       <aop:advisor advice-ref="log" pointcut-ref="point"/>
       <aop:advisor advice-ref="afterLog" pointcut-ref="point"/>
    </aop:config>
          

</beans>

方式二:使用自定义类实现切面。

自定义类如下:

package SpringAop;

public class DivPointCut 
{
	public void before()
	{
		System.out.println("----方法执行前----");
	}
	public void after()
	{
		System.out.println("----方法执行后----");
	}

}

Spring配置文件如下:

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
 
  <!-- 使用注释<context:component-scan base-package="SpringAop"/> -->
    <bean id="log" class="SpringAop.Log"></bean>
    <bean id="afterLog" class="SpringAop.AfterLog"></bean>
    <bean id="userService" class="SpringAop.UserServiceImp"></bean>
     
     <!-- 方式一:使用Spring原生的API -->   
     <!-- 配置AOP -->
    <!-- <aop:config>
       切入点:expression:表达式;execution():要执行的位置:
       <aop:pointcut id="point" expression="execution(* SpringAop.UserServiceImp.*(..))"/>
       执行环绕
       <aop:advisor advice-ref="log" pointcut-ref="point"/>
       <aop:advisor advice-ref="afterLog" pointcut-ref="point"/>
    </aop:config> -->
    
    <!--方法二:自定义类 -->
    <bean id="diy" class="SpringAop.DivPointCut "></bean>
      
    <aop:config>
    <!-- 自定义切面,ref要引用的类 -->
      <aop:aspect ref="diy">
      <aop:pointcut id="point" expression="execution(* SpringAop.UserServiceImp.*(..))"></aop:pointcut>
      <aop:before pointcut-ref="point" method="before()"/>
      <aop:after pointcut-ref="point" method="after()"/>
      </aop:aspect>
    </aop:config>    

</beans>

方式三:使用注解实现AOP

Spring配置文件如下:

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
 
  <!-- 使用注释<context:component-scan base-package="SpringAop"/> -->
    <bean id="log" class="SpringAop.Log"></bean>
    <bean id="afterLog" class="SpringAop.AfterLog"></bean>
    <bean id="userService" class="SpringAop.UserServiceImp"></bean>
     
     <!-- 方式一:使用Spring原生的API -->   
     <!-- 配置AOP -->
    <!-- <aop:config>
       切入点:expression:表达式;execution():要执行的位置:
       <aop:pointcut id="point" expression="execution(* SpringAop.UserServiceImp.*(..))"/>
       执行环绕
       <aop:advisor advice-ref="log" pointcut-ref="point"/>
       <aop:advisor advice-ref="afterLog" pointcut-ref="point"/>
    </aop:config> -->
    
    <!--方法二:自定义类 -->
    <!-- <bean id="diy" class="SpringAop.DivPointCut "></bean>
      
    <aop:config>
    自定义切面,ref要引用的类
      <aop:aspect ref="diy">
      <aop:pointcut id="point" expression="execution(* SpringAop.UserServiceImp.*(..))"></aop:pointcut>
      <aop:before pointcut-ref="point" method="before()"/>
      <aop:after pointcut-ref="point" method="after()"/>
      </aop:aspect>
    </aop:config>     -->
    
        <!--方法三:自定义类 -->
     <bean id="anotationPointCut" class="SpringAop.AnotationPointCut"></bean>  
     <!-- 开启注释支持 JDK(默认 proxy-target-class="false" cglib("true")) -->
     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

相应的实现代码如下:

package SpringAop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

//方式三:使用注解方式实现AOP

@Aspect //标记这个类是一个问题
public class AnotationPointCut 
{
	@Before("execution(* SpringAop.UserServiceImp.*(..))")
	public void before()
	{
		System.out.println("----方法执行前----");
	}
	@After("execution(* SpringAop.UserServiceImp.*(..))")
	public void after()
	{
		System.out.println("----方法执行后----");
	}
	//在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
	@Around("execution(* SpringAop.UserServiceImp.*(..))")
	public void around(ProceedingJoinPoint jp) throws Throwable
	{
		System.out.println("环绕前");
		System.out.println(jp.getSignature());//获得签名
		//执行方法
		Object proceed=jp.proceed();
		System.out.println("环绕哦后");
	}

}

<think>好的,我现在要解决用户提到的两个主要问题:MySQL连接错误导致主机被阻塞,以及Public Key Retrieval不允许的问题。用户还提到使用Spring AOP和Hikari数据源,所以我需要确保解决方案适用于这些技术栈。 首先,关于主机被阻塞的问题,用户之前已经得到了一些解决步骤,比如使用`FLUSH HOSTS`和调整`max_connect_errors`参数。现在用户可能遇到了同样的问题,或者之前的解决方案没有完全解决问题,需要进一步排查。我需要检查是否有其他原因导致连接错误,比如网络问题、错误的连接配置或者权限问题。此外,用户提到的Hikari数据源可能需要特定的配置来防止过多的连接尝试失败,比如合理设置连接池的大小和超时时间。 接下来是Public Key Retrieval不允许的问题。根据用户提供的引用,这个问题通常出现在MySQL 8.x版本,连接驱动需要特定的配置参数,比如在JDBC URL中添加`allowPublicKeyRetrieval=true`和`useSSL=false`。用户可能已经按照建议修改了连接字符串,但问题仍然存在,或者配置没有正确应用。需要检查Spring Boot的配置文件,确保驱动类名正确(com.mysql.cj.jdbc.Driver),并且所有参数都正确无误。此外,用户可能使用的是旧版本的MySQL驱动,需要升级到与MySQL 8.x兼容的版本,比如8.0.25以上。 用户还提到了Spring AOP,这可能涉及到事务管理或连接池的监控。需要确认AOP配置是否无意中修改了连接属性,或者导致连接未被正确释放,从而引发连接错误。同时,Hikari作为高性能的连接池,配置不当可能导致连接泄露或过多连接尝试,需要检查Hikari的配置参数,如最大连接数、空闲超时时间等。 另外,用户提到的错误中有一个只读连接的异常(Connection is read-only),这可能是因为在事务管理中默认设置了只读,或者在数据源配置中没有正确设置读写权限。需要检查Spring的事务注解(如@Transactional)是否指定了readOnly=false,以及数据源配置是否允许写操作。 综合来看,用户的问题可能涉及多个方面:MySQL服务器配置、JDBC连接参数、驱动版本、Hikari连接池配置、Spring事务管理以及可能的网络或权限问题。需要逐一排查这些方面,确保每一步配置都正确,并且各部分协同工作正常。此外,用户可能需要查看MySQL的错误日志以获取更详细的错误信息,帮助定位问题根源。</think>针对MySQL连接错误和Public Key Retrieval问题,结合Spring AOP和Hikari数据源配置,按以下步骤解决: --- ### 一、同步解决两个核心问题 #### 问题1:Host Blocked错误 **直接解决方案**: ```bash # 通过命令行解除阻塞 mysqladmin -u root -p flush-hosts ``` 或登录MySQL执行: ```sql FLUSH HOSTS; -- 清除错误计数器[^4] ``` **永久预防配置**: 修改MySQL配置文件`my.cnf`: ```ini [mysqld] max_connect_errors=1000 -- 提高错误阈值 wait_timeout=300 -- 减少空闲连接 ``` #### 问题2:Public Key Retrieval错误 **JDBC连接配置修正**: 在Spring Boot的`application.yml`中添加参数: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/db_name?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driver # 必须使用cj驱动 ``` --- ### 二、Hikari连接池优化配置 ```yaml spring: datasource: hikari: maximum-pool-size: 10 # 根据业务需求调整 connection-timeout: 30000 # 连接超时时间(ms) idle-timeout: 600000 # 空闲连接超时时间 max-lifetime: 1800000 # 连接最大存活时间 connection-test-query: SELECT 1 # MySQL健康检查语句 ``` --- ### 三、Spring事务与AOP协同配置 1. **禁用只读模式**: ```java @Transactional(readOnly = false) // 在写操作的方法上明确声明 public void updateData(){...} ``` 2. **AOP拦截器示例**(监控连接异常): ```java @Aspect @Component public class DataSourceAspect { @AfterThrowing(pointcut = "execution(* com.yourpackage..*(..))", throwing = "ex") public void handleConnectionException(SQLException ex) { if(ex.getErrorCode() == 1129) { // Host blocked错误码 System.out.println("触发主机阻塞异常,建议检查连接配置"); } } } ``` --- ### 四、驱动版本验证 ```xml <!-- pom.xml必须使用8.x驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> <!-- 推荐稳定版本 --> </dependency> ``` --- ### 、错误日志排查技巧 1. **查看Hikari运行状态**: ```java HikariDataSource ds = (HikariDataSource)dataSource; System.out.println(ds.getHikariPoolMXBean().getActiveConnections()); ``` 2. **MySQL错误日志定位**: ```bash tail -f /var/log/mysql/mysql.log # 实时查看连接错误日志 ``` --- ### 六、补充验证步骤 1. **SSL证书验证**: ```bash openssl s_client -connect 10.251.22.248:3306 # 检查SSL握手是否成功 ``` 2. **网络连通性测试**: ```bash telnet 10.251.22.248 3306 # 确认端口可达性 ``` --- ### 七、完整配置示例 ```yaml # application.yml完整配置参考 spring: datasource: url: jdbc:mysql://10.251.22.248:3306/db?useSSL=false&allowPublicKeyRetrieval=true&autoReconnect=true username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver hikari: maximum-pool-size: 15 connection-timeout: 10000 validation-timeout: 5000 ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值